PluginProbe
WP-Stateless – Google Cloud Storage / trunk
WP-Stateless – Google Cloud Storage vtrunk
4.4.3 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.3.0 2.3.1 2.3.2 3.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 All 62 releases
← All changes | lib/classes/class-utility.php +104 -35 3.2.2trunk View file →
@@ -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 }