| @@ -45,17 +45,8 @@ | ||
| 45 | 45 | } |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | /** |
| 49 | - * Override Cache Control | |
| 50 | - * @param $cacheControl | |
| 51 | - * @return mixed | |
| 52 | - */ | |
| 53 | - public static function override_cache_control($cacheControl) { | |
| 54 | - return ud_get_stateless_media()->get('sm.cache_control'); | |
| 55 | - } | |
| 56 | - | |
| 57 | - /** | |
| 58 | 49 | * wp_normalize_path was added in 3.9.0 |
| 59 | 50 | * |
| 60 | 51 | * @param $path |
| 61 | 52 | * @return mixed|string |
| @@ -138,19 +129,15 @@ | ||
| 138 | 129 | } |
| 139 | 130 | |
| 140 | 131 | $_mime_type = get_post_mime_type($attachment_id); |
| 141 | 132 | |
| 142 | - // Treat images as public. | |
| 143 | - if (strpos($_mime_type, 'image/') !== false) { | |
| 144 | - return apply_filters('sm:item:cacheControl', 'public, max-age=36000, must-revalidate', array('attachment_id' => $attachment_id, 'mime_type' => null, 'metadata' => $metadata, 'data' => $data)); | |
| 145 | - } | |
| 146 | - | |
| 147 | - // Treat images as public. | |
| 133 | + // Treat SQL as non-public. | |
| 148 | 134 | if (strpos($_mime_type, 'sql') !== false) { |
| 149 | 135 | return apply_filters('sm:item:cacheControl', 'private, no-cache, no-store', array('attachment_id' => $attachment_id, 'mime_type' => null, 'metadata' => $metadata, 'data' => $data)); |
| 150 | 136 | } |
| 151 | 137 | |
| 152 | - return apply_filters('sm:item:cacheControl', 'public, max-age=30, no-store, must-revalidate', array('attachment_id' => $attachment_id, 'mime_type' => null, 'metadata' => $metadata, 'data' => $data)); | |
| 138 | + // Treat all other files as public. | |
| 139 | + return apply_filters('sm:item:cacheControl', ud_get_stateless_media()->get_default_cache_control(), array('attachment_id' => $attachment_id, 'mime_type' => null, 'metadata' => $metadata, 'data' => $data)); | |
| 153 | 140 | } |
| 154 | 141 | |
| 155 | 142 | /** |
| 156 | 143 | * Add/Update Media to Bucket |
| @@ -253,9 +240,9 @@ | ||
| 253 | 240 | $metadata["file"] = $file; |
| 254 | 241 | } |
| 255 | 242 | } |
| 256 | 243 | |
| 257 | - $cloud_meta = get_post_meta($attachment_id, 'sm_cloud', true); | |
| 244 | + $cloud_meta = apply_filters('wp_stateless_get_file', [], $attachment_id, true); | |
| 258 | 245 | |
| 259 | 246 | $cloud_meta = wp_parse_args($cloud_meta, array( |
| 260 | 247 | 'name' => '', |
| 261 | 248 | 'bucket' => ud_get_stateless_media()->get('sm.bucket'), |
| @@ -279,8 +266,9 @@ | ||
| 279 | 266 | $metadata['filesize'] = $cloud_meta['filesize']; |
| 280 | 267 | } |
| 281 | 268 | |
| 282 | 269 | $image_sizes = self::get_path_and_url($metadata, $attachment_id); |
| 270 | + | |
| 283 | 271 | foreach ($image_sizes as $size => $img) { |
| 284 | 272 | if ((isset($_REQUEST['size']) && $_REQUEST['size'] == $size) || empty($_REQUEST['size'])) { |
| 285 | 273 | // GCS metadata |
| 286 | 274 | $_metadata = array( |
| @@ -308,9 +296,10 @@ | ||
| 308 | 296 | 'cacheControl' => $_cacheControl, |
| 309 | 297 | 'contentDisposition' => $_contentDisposition, |
| 310 | 298 | )); |
| 311 | 299 | |
| 312 | - if ($sm_mode == 'stateless' && !wp_doing_ajax() && !wp_doing_cron()) { | |
| 300 | + if ($sm_mode == 'stateless' && !wp_doing_ajax() && !wp_doing_cron() | |
| 301 | + || ($sm_mode == 'stateless' && wp_doing_ajax()) ) { | |
| 313 | 302 | global $gs_client; |
| 314 | 303 | |
| 315 | 304 | $media_args = wp_parse_args($media_args, array( |
| 316 | 305 | 'use_root' => true, |
| @@ -333,21 +322,23 @@ | ||
| 333 | 322 | * Updating object metadata, ACL, CacheControl and contentDisposition |
| 334 | 323 | * @return media object |
| 335 | 324 | */ |
| 336 | 325 | try { |
| 337 | - $media = $object->update(array('metadata' => $media_args['metadata']) + | |
| 338 | - array( | |
| 339 | - 'cacheControl' => $_cacheControl, | |
| 340 | - 'predefinedAcl' => 'publicRead', | |
| 341 | - 'contentDisposition' => $_contentDisposition | |
| 342 | - )); | |
| 326 | + $mediaOptions = array( | |
| 327 | + 'cacheControl' => $_cacheControl, | |
| 328 | + 'contentDisposition' => $_contentDisposition | |
| 329 | + ); | |
| 343 | 330 | |
| 331 | + if ( !defined('WP_STATELESS_SKIP_ACL_SET') || !WP_STATELESS_SKIP_ACL_SET) { | |
| 332 | + $mediaOptions['predefinedAcl'] = 'publicRead'; | |
| 333 | + } | |
| 334 | + | |
| 335 | + $media = $object->update(array('metadata' => $media_args['metadata']) + $mediaOptions); | |
| 336 | + | |
| 344 | 337 | $cloud_meta = self::generate_cloud_meta($cloud_meta, $media, $size, $img, $bucketLink); |
| 345 | 338 | } catch (\Throwable $th) { |
| 346 | 339 | //throw $th; |
| 347 | 340 | } |
| 348 | - | |
| 349 | - $cloud_meta = self::generate_cloud_meta($cloud_meta, $media, $size, $img, $bucketLink); | |
| 350 | 341 | } else { |
| 351 | 342 | /* Add default image */ |
| 352 | 343 | $media = $client->add_media($media_args); |
| 353 | 344 | |
| @@ -720,11 +711,57 @@ | ||
| 720 | 711 | return false; |
| 721 | 712 | } |
| 722 | 713 | |
| 723 | 714 | /** |
| 724 | - * Generate JWT token signed by current site AUTH_SALT | |
| 725 | - * If no AUTH_SALT defined - admin email used | |
| 715 | + * Get a secure JWT signing key | |
| 716 | + * Priority: AUTH_SALT (if valid length) > Plugin-specific stored key > Generated key | |
| 726 | 717 | * |
| 718 | + * @return string A key suitable for HS256 (minimum 32 bytes) | |
| 719 | + */ | |
| 720 | + public static function get_jwt_signing_key() { | |
| 721 | + // Minimum key length for HS256 (256 bits = 32 bytes) | |
| 722 | + $min_key_length = 32; | |
| 723 | + | |
| 724 | + // Try AUTH_SALT first if it's long enough | |
| 725 | + if (defined('AUTH_SALT') && !empty(AUTH_SALT) && strlen(AUTH_SALT) >= $min_key_length) { | |
| 726 | + return AUTH_SALT; | |
| 727 | + } | |
| 728 | + | |
| 729 | + // Try to get stored plugin-specific key | |
| 730 | + $stored_key = get_option('wp_stateless_jwt_key'); | |
| 731 | + | |
| 732 | + if ($stored_key && strlen($stored_key) >= $min_key_length) { | |
| 733 | + return $stored_key; | |
| 734 | + } | |
| 735 | + | |
| 736 | + // Generate a new secure key | |
| 737 | + $new_key = self::generate_secure_key($min_key_length); | |
| 738 | + update_option('wp_stateless_jwt_key', $new_key, false); | |
| 739 | + | |
| 740 | + return $new_key; | |
| 741 | + } | |
| 742 | + | |
| 743 | + /** | |
| 744 | + * Generate a cryptographically secure random key | |
| 745 | + * | |
| 746 | + * @param int $length Key length in bytes | |
| 747 | + * @return string Base64-encoded key | |
| 748 | + */ | |
| 749 | + private static function generate_secure_key($length = 32) { | |
| 750 | + try { | |
| 751 | + // Use random_bytes for PHP 7+ | |
| 752 | + $random_bytes = random_bytes($length); | |
| 753 | + return base64_encode($random_bytes); | |
| 754 | + } catch (\Exception $e) { | |
| 755 | + // Fallback: use wp_generate_password | |
| 756 | + return wp_generate_password($length * 2, true, true); | |
| 757 | + } | |
| 758 | + } | |
| 759 | + | |
| 760 | + /** | |
| 761 | + * Generate JWT token signed by secure key | |
| 762 | + * Uses AUTH_SALT if valid, otherwise uses plugin-specific stored key | |
| 763 | + * | |
| 727 | 764 | * @param $payload |
| 728 | 765 | * @param int $ttl |
| 729 | 766 | * @return string |
| 730 | 767 | */ |
| @@ -735,15 +772,15 @@ | ||
| 735 | 772 | 'aud' => $site_url, |
| 736 | 773 | 'exp' => $now + $ttl |
| 737 | 774 | ]); |
| 738 | 775 | |
| 739 | - $key = defined('AUTH_SALT') ? AUTH_SALT : get_option('admin_email'); | |
| 776 | + $key = self::get_jwt_signing_key(); | |
| 740 | 777 | return JWT::encode($payload, $key, 'HS256'); |
| 741 | 778 | } |
| 742 | 779 | |
| 743 | 780 | /** |
| 744 | 781 | * Verify and decode token |
| 745 | - * If no AUTH_SALT defined - admin email used | |
| 782 | + * Uses the same secure key retrieval as generation | |
| 746 | 783 | * Throws exceptions if cannot decode |
| 747 | 784 | * |
| 748 | 785 | * @param $token |
| 749 | 786 | * @return object |
| @@ -749,9 +786,9 @@ | ||
| 749 | 786 | * @return object |
| 750 | 787 | * @throws \Exception |
| 751 | 788 | */ |
| 752 | 789 | public static function verify_jwt_token($token) { |
| 753 | - $key = defined('AUTH_SALT') ? AUTH_SALT : get_option('admin_email'); | |
| 790 | + $key = self::get_jwt_signing_key(); | |
| 754 | 791 | return JWT::decode($token, new Key($key, 'HS256')); |
| 755 | 792 | } |
| 756 | 793 | |
| 757 | 794 | /** |
| @@ -920,13 +957,20 @@ | ||
| 920 | 957 | */ |
| 921 | 958 | public static function get_stateless_media_data_count() { |
| 922 | 959 | global $wpdb; |
| 923 | 960 | |
| 961 | + if ( !ud_get_stateless_media()->get('sm.use_postmeta') ) { | |
| 962 | + try { | |
| 963 | + return ud_stateless_db()->get_total_files(); | |
| 964 | + } catch (\Throwable $th) { | |
| 965 | + } | |
| 966 | + } | |
| 967 | + | |
| 924 | 968 | $stateless_media = $wpdb->get_var($wpdb->prepare(" |
| 925 | - SELECT COUNT(meta_id) | |
| 926 | - FROM " . $wpdb->postmeta . " | |
| 927 | - WHERE meta_key = %s | |
| 928 | - ", 'sm_cloud')); | |
| 969 | + SELECT COUNT(meta_id) | |
| 970 | + FROM " . $wpdb->postmeta . " | |
| 971 | + WHERE meta_key = %s | |
| 972 | + ", 'sm_cloud')); | |
| 929 | 973 | |
| 930 | 974 | return $stateless_media; |
| 931 | 975 | } |
| 932 | 976 | |
| @@ -1084,8 +1128,33 @@ | ||
| 1084 | 1128 | } |
| 1085 | 1129 | } |
| 1086 | 1130 | |
| 1087 | 1131 | return $file; |
| 1132 | + } | |
| 1133 | + | |
| 1134 | + /** | |
| 1135 | + * Return list of files in a dir. | |
| 1136 | + * @param string $dir: Directory path | |
| 1137 | + * @return array - Lists of files in the directory and subdirectory. | |
| 1138 | + */ | |
| 1139 | + public static function get_files($dir) { | |
| 1140 | + $return = array(); | |
| 1141 | + if (is_dir($dir) && $dh = opendir($dir)) { | |
| 1142 | + while ($file = readdir($dh)) { | |
| 1143 | + if ($file != '.' && $file != '..') { | |
| 1144 | + if (is_dir($dir . $file)) { | |
| 1145 | + // since it is a directory we recursively get files. | |
| 1146 | + $arr = self::get_files($dir . $file . '/'); | |
| 1147 | + $return = array_merge($return, $arr); | |
| 1148 | + } else { | |
| 1149 | + $return[] = $dir . $file; | |
| 1150 | + } | |
| 1151 | + } | |
| 1152 | + } | |
| 1153 | + closedir($dh); | |
| 1154 | + } | |
| 1155 | + | |
| 1156 | + return $return; | |
| 1088 | 1157 | } |
| 1089 | 1158 | } |
| 1090 | 1159 | } |
| 1091 | 1160 | } |