From 43443087b0e0d6d0c98d30575c0304d9c205e05b Mon Sep 17 00:00:00 2001 From: Kimberly Date: Fri, 3 Feb 2017 15:17:24 -0500 Subject: [PATCH] [0.9.4.x] - readying a new release (#355) just readying a new release for the 0.9.4.x generation users. --- README.md | 11 +- changelog.txt | 8 + inc/define.php | 2 +- inc/options/browsercache.php | 316 ++++++++++++++++++++++++ inc/options/cdn.php | 6 + inc/options/cdn/cf.php | 2 +- inc/options/cdn/s3.php | 2 +- inc/options/common/header.php | 3 +- lib/S3.php | 3 +- lib/W3/AdminActions/CdnActionsAdmin.php | 2 +- lib/W3/BrowserCacheAdminEnvironment.php | 177 +++++++++++++ lib/W3/Cli.php | 60 ++--- lib/W3/ConfigKeys.php | 133 +++++++++- lib/W3/PgCache.php | 31 +-- lib/W3/Plugin/Cdn.php | 45 ++++ lib/W3/SharedPageUrls.php | 12 +- lib/W3/UI/Settings/BrowserCache.php | 33 ++- lib/W3/UI/Settings/CDN.php | 1 + pub/css/options.css | 13 +- pub/img/cspref.png | Bin 0 -> 48720 bytes pub/js/options.js | 81 +++++- readme.txt | 10 +- w3-total-cache-fixed.php | 2 +- 23 files changed, 887 insertions(+), 66 deletions(-) create mode 100644 pub/img/cspref.png diff --git a/README.md b/README.md index cbb2c4f..af26533 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,12 @@ Make sure you select the correct generation that fits your environment. | Generation | Date |Version | Download Link | ------------- |:-------------:|:-----:|-----| -| For 0.9.4.x Users | 2017-01-19 | 0.9.4.6.2| [w3-total-cache-fixed-(for-v0.9.4.x-users).zip](https://github.com/szepeviktor/w3-total-cache-fixed/releases/download/0.9.4.6.2/w3-total-cache-fixed-for-v0.9.4.x-users.zip) -| For 0.9.5.x Users | --- | --- | _coming soon_ +| For 0.9.4.x Users | 2017-02-03 | 0.9.4.6.3 | [w3-total-cache-fixed-(for-v0.9.4.x-users).zip](https://github.com/szepeviktor/w3-total-cache-fixed/releases/download/0.9.4.6.3/w3-total-cache-fixed-for-v0.9.4.x-users.zip) +| For 0.9.5.x Users | 2017-02-02 | 0.9.5.2.2 | [w3-total-cache-fixed-(for-v0.9.5.x-users).zip](https://github.com/szepeviktor/w3-total-cache-fixed/releases/download/0.9.5.2.2/w3-total-cache-fixed-for-v0.9.5.x-users.zip) --- -### Installation +### Installation (for v0.9.4.x Users) _**Note:** After the following steps, all future updates and installations will be handled from within WordPress._ 1. Deactivate (but don't delete) your existing W3 Total Cache plugin (if installed) from within WordPress' Plugin page. @@ -42,9 +42,10 @@ _**Note:** This list does not reflect all of the myriad of fixes/changes -- just ![DONE] Removed Deprecated WordPress Code
![DONE] Full PHP7 Compliancy (Passes [PHPCompatibility](https://github.com/wimg/PHPCompatibility): 100%)
-![DONE] Amazon Web Services (AWS) v4 Signature Support (IPv4 & IPv6) with New Endpoints/Regions
+![DONE] Security Headers Management for X-Frame-Options, X-XSS-Protection, X-Content-Type-Options, HPKP, CSP, HSTS policy
+![DONE] Amazon Web Services (AWS) v4 Signature Support (IPv4 & IPv6) with All Endpoints/Regions
![DONE] Option to Embed Minified JS and CSS Content Directly into HTML Page
-![DONE] Extended WP-CLI Support
+![DONE] Extended WP-CLI Support, including Priming the Page Cache Asynchronously
![DONE] Memcache & Memcached Extension Support
![DONE] APCu Support
![DONE] OPcache Support
diff --git a/changelog.txt b/changelog.txt index e6a5622..d63e8b3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,11 @@ += 0.9.4.6.3 = +* Security Headers section added to Browser Cache -- X-Frame-Options, X-XSS-Protection, X-Content-Type-Options, HTTP Public Key Pinning, Content Security Policy, HTTP Strict Transport Security, and Session Cookies +* Checkbox under CDN to allow CDN URLs to be used for the Media Library when on admin pages +* Bug fix to Amazon Web Services (AWS) Cloudfront (origin pull) distributions +* Bug fix for page cache's categories, tags, author, and custom fields +* WP-CLI prime - tweak for sitemaps +* Bug fix to now allow flushing of a post/page's cache when changing from published to draft/pending review + = 0.9.4.6.2 = * Fixed a strict mode error specific to PHP 5.4/5.6 users * Configuration file loader adjustment to handle a case of someone going from v0.9.5.2+ to v0.9.4.x diff --git a/inc/define.php b/inc/define.php index 7bc2921..a07e891 100644 --- a/inc/define.php +++ b/inc/define.php @@ -5,7 +5,7 @@ } define('W3TC', true); -define('W3TC_VERSION', '0.9.4.6.2'); +define('W3TC_VERSION', '0.9.4.6.3'); define("W3TC_TESTED_ON_WP_VERSION", '4.7.1'); define('W3TC_POWERED_BY', 'W3 Total Cache/' . W3TC_VERSION); define('W3TC_EMAIL', 'w3tc@w3-edge.com'); diff --git a/inc/options/browsercache.php b/inc/options/browsercache.php index a648d33..7eec860 100644 --- a/inc/options/browsercache.php +++ b/inc/options/browsercache.php @@ -374,6 +374,322 @@

postbox_footer(); ?> + + postbox_header(__('Security Headers', 'w3-total-cache'), '', 'security'); ?> +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ checkbox( 'browsercache.security.session.cookie_httponly' ) ?> +
+
+ checkbox( 'browsercache.security.session.cookie_secure' ) ?> +
+
+ checkbox( 'browsercache.security.session.use_only_cookies' ) ?> +
+
+ checkbox( 'browsercache.security.hsts' ) ?> +
SSL/TLS) connections to the server. This can help mitigate adverse effects caused by bugs and session leaks through cookies and links. It also helps defend against man-in-the-middle attacks. If there are SSL negotiation warnings then users will not be permitted to ignore them.', 'w3-total-cache' ); ?> +
+ + + +
+
+ checkbox( 'browsercache.security.xfo' ) ?> +
+
+ + + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.xfo.allow' ) ); ?>" size="50" placeholder="Enter URL" /> +
+
+ checkbox( 'browsercache.security.xss' ) ?> +
+
+ + + +
+
+ checkbox( 'browsercache.security.xcto' ) ?> +
+
+ checkbox( 'browsercache.security.pkp' ) ?> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.pkp.pin' ) ); ?>" size="50" placeholder="Enter the Base64-Encode of the SHA256 Hash" /> +
required and represents a SPKI fingerprint. This pin is any public key within your current certificate chain.' ); ?>
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.pkp.pin.backup' ) ); ?>" size="50" placeholder="Enter the Base64-Encode of the SHA256 Hash" /> +
also required and represents your backup SPKI fingerprint. This pin is any public key not in your current certificate chain and serves as backup in case your certificate expires or has to be revoked.' ); ?>
+
+ + + +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.pkp.report.url' ) ); ?>" size="50" placeholder="Enter URL" /> +
+
+ + + +
+
+ checkbox( 'browsercache.security.csp' ) ?> +
+

Quick Reference Chart

+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.base' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.connect' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.font' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.frame' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.img' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.media' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.object' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.script' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.style' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.form' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.frame' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.plugin' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.sandbox' ) ); ?>" size="50" /> +
+
+ + + sealing_disabled( 'browsercache' ) ?> value="_config->get_string( 'browsercache.security.csp.default' ) ); ?>" size="50" /> +
+
+

+ nonce_field('w3tc'); ?> + +

+ postbox_footer(); ?> diff --git a/inc/options/cdn.php b/inc/options/cdn.php index 2e4f50e..82e8405 100644 --- a/inc/options/cdn.php +++ b/inc/options/cdn.php @@ -164,6 +164,12 @@ When SSL pages are returned no CDN URLs will appear in HTML pages. + + + checkbox( 'cdn.admin.media_library' ) ?>
+ All Media Library content will use CDN links on administration pages. + + checkbox('cdn.reject.logged_roles') ?>
diff --git a/inc/options/cdn/cf.php b/inc/options/cdn/cf.php index 50249d5..4aa9999 100644 --- a/inc/options/cdn/cf.php +++ b/inc/options/cdn/cf.php @@ -29,7 +29,7 @@ - + diff --git a/inc/options/cdn/s3.php b/inc/options/cdn/s3.php index c5cec2d..e0997c5 100644 --- a/inc/options/cdn/s3.php +++ b/inc/options/cdn/s3.php @@ -29,7 +29,7 @@ - + diff --git a/inc/options/common/header.php b/inc/options/common/header.php index ddb332b..8b7cbf3 100644 --- a/inc/options/common/header.php +++ b/inc/options/common/header.php @@ -164,7 +164,8 @@ | CSS & JS', 'w3-total-cache'); ?> | HTML & XML', 'w3-total-cache'); ?> | - + | +

endpoint = $endpoint; $this->verb = $verb; - $this->bucket = strtolower($bucket); + $this->bucket = $bucket; $this->uri = $uri !== '' ? '/'.str_replace('%2F', '/', rawurlencode($uri)) : '/'; if ($this->bucket !== '') @@ -2207,7 +2207,6 @@ function __construct($verb, $bucket = '', $uri = '', $endpoint = 's3.amazonaws.c else { $this->headers['Host'] = $this->endpoint; - $this->uri = $this->uri; if ($this->bucket !== '') $this->uri = '/'.$this->bucket.$this->uri; $this->bucket = ''; $this->resource = $this->uri; diff --git a/lib/W3/AdminActions/CdnActionsAdmin.php b/lib/W3/AdminActions/CdnActionsAdmin.php index 13d5586..fb39356 100644 --- a/lib/W3/AdminActions/CdnActionsAdmin.php +++ b/lib/W3/AdminActions/CdnActionsAdmin.php @@ -483,7 +483,7 @@ function action_cdn_s3_bucket_location() { 'us-east-2' => __('US East (Ohio)', 'w3-total-cache'), 'us-west-1' => __('US-West (N. California)', 'w3-total-cache'), 'us-west-2' => __('US-West (Oregon)', 'w3-total-cache'), - 'ca-central-1' => __('Canada (Central)', 'w3-total-cache'), + 'ca-central-1' => __('Canada (Montreal)', 'w3-total-cache'), 'ap-south-1' => __('Asia Pacific (Mumbai)', 'w3-total-cache'), 'ap-northeast-2'=> __('Asia Pacific (Seoul)', 'w3-total-cache'), 'ap-southeast-1'=> __('Asia Pacific (Singapore)', 'w3-total-cache'), diff --git a/lib/W3/BrowserCacheAdminEnvironment.php b/lib/W3/BrowserCacheAdminEnvironment.php index cddb8da..9345183 100644 --- a/lib/W3/BrowserCacheAdminEnvironment.php +++ b/lib/W3/BrowserCacheAdminEnvironment.php @@ -328,6 +328,100 @@ private function rules_cache_generate_apache($config) { $rules .= $this->_rules_cache_generate_apache_for_type($config, $extensions, $type); + $sec = " php_flag session.cookie_httponly " . ( $config->get_boolean( 'browsercache.security.session.cookie_httponly' ) ? "on" : "off" ) . "\n" . + " php_flag session.cookie_secure " . ( $config->get_boolean( 'browsercache.security.session.cookie_secure' ) ? "on" : "off" ) . "\n" . + " php_flag session.use_only_cookies " . ( $config->get_boolean( 'browsercache.security.session.use_only_cookies' ) ? "on" : "off" ) . "\n\n"; + + $rules .= "\n"; + $rules .= $sec; + $rules .= "\n"; + $rules .= $sec; + $rules .= "\n"; + $rules .= $sec; + + if ( $config->get_boolean( 'browsercache.security.hsts' ) || + $config->get_boolean( 'browsercache.security.xfo' ) || + $config->get_boolean( 'browsercache.security.xss' ) || + $config->get_boolean( 'browsercache.security.xcto' ) || + $config->get_boolean( 'browsercache.security.pkp' ) || + $config->get_boolean( 'browsercache.security.csp' ) + ) { + $lifetime = $config->get_integer( 'browsercache.other.lifetime' ); + + $rules .= "\n"; + + if ( $config->get_boolean( 'browsercache.security.hsts' ) ) { + $dir = $config->get_string( 'browsercache.security.hsts.directive' ); + $rules .= " Header set Strict-Transport-Security \"max-age=$lifetime" . ( strpos( $dir,"inc" ) ? "; includeSubDomains" : "" ) . ( strpos( $dir, "pre" ) ? "; preload" : "" ) . "\"\n"; + } + + if ( $config->get_boolean( 'browsercache.security.xfo' ) ) { + $dir = $config->get_string( 'browsercache.security.xfo.directive' ); + $url = trim( $config->get_string( 'browsercache.security.xfo.allow' ) ); + if ( empty( $url ) ) { + $url = w3_get_url_ssl(w3_get_home_url()); + } + $rules .= " Header always append X-Frame-Options \"" . ( $dir == "same" ? "SAMEORIGIN" : ( $dir == "deny" ? "DENY" : "ALLOW-FROM $url" ) ) . "\"\n"; + } + + if ( $config->get_boolean( 'browsercache.security.xss' ) ) { + $dir = $config->get_string( 'browsercache.security.xss.directive' ); + $rules .= " Header set X-XSS-Protection \"" . ( $dir == "block" ? "1; mode=block" : $dir ) . "\"\n"; + + } + + if ( $config->get_boolean( 'browsercache.security.xcto' ) ) { + $rules .= " Header set X-Content-Type-Options \"nosniff\"\n"; + } + + if ( $config->get_boolean( 'browsercache.security.pkp' ) ) { + $pin = trim( $config->get_string( 'browsercache.security.pkp.pin' ) ); + $pinbak = trim( $config->get_string( 'browsercache.security.pkp.pin.backup' ) ); + $extra = $config->get_string( 'browsercache.security.pkp.extra' ); + $url = trim( $config->get_string( 'browsercache.security.pkp.report.url' ) ); + $rep_only = $config->get_string( 'browsercache.security.pkp.report.only' ) == '1' ? true : false; + $rules .= " Header set " . ( $rep_only ? "Public-Key-Pins-Report-Only" : "Public-Key-Pins" ) . " \"pin-sha256=\\\"$pin\\\"; pin-sha256=\\\"$pinbak\\\"; max-age=$lifetime" . ( strpos( $extra,"inc" ) ? "; includeSubDomains" : "" ) . ( !empty( $url ) ? "; report-uri=\\\"$url\\\"" : "" ) . "\"\n"; + } + + if ( $config->get_boolean( 'browsercache.security.csp' ) ) { + $base = trim( $config->get_string( 'browsercache.security.csp.base' ) ); + $frame = trim( $config->get_string( 'browsercache.security.csp.frame' ) ); + $connect = trim( $config->get_string( 'browsercache.security.csp.connect' ) ); + $font = trim( $config->get_string( 'browsercache.security.csp.font' ) ); + $script = trim( $config->get_string( 'browsercache.security.csp.script' ) ); + $style = trim( $config->get_string( 'browsercache.security.csp.style' ) ); + $img = trim( $config->get_string( 'browsercache.security.csp.img' ) ); + $media = trim( $config->get_string( 'browsercache.security.csp.media' ) ); + $object = trim( $config->get_string( 'browsercache.security.csp.object' ) ); + $plugin = trim( $config->get_string( 'browsercache.security.csp.plugin' ) ); + $form = trim( $config->get_string( 'browsercache.security.csp.form' ) ); + $frame_ancestors = trim( $config->get_string( 'browsercache.security.csp.frame.ancestors' ) ); + $sandbox = $config->get_string( 'browsercache.security.csp.sandbox' ); + $default = trim( $config->get_string( 'browsercache.security.csp.default' ) ); + + $dir = rtrim( ( !empty( $base ) ? "base-uri $base; " : "" ). + ( !empty( $frame ) ? "frame-src $frame; " : "" ). + ( !empty( $connect ) ? "connect-src $connect; " : "" ). + ( !empty( $font ) ? "font-src $font; " : "" ). + ( !empty( $script ) ? "script-src $script; " : "" ). + ( !empty( $style ) ? "style-src $style; " : "" ). + ( !empty( $img ) ? "img-src $img; " : "" ). + ( !empty( $media ) ? "media-src $media; " : "" ). + ( !empty( $object ) ? "object-src $object; " : "" ). + ( !empty( $plugin ) ? "plugin-types $plugin; " : "" ). + ( !empty( $form ) ? "form-action $form; " : "" ). + ( !empty( $frame_ancestors ) ? "frame-ancestors $frame_ancestors; " : "" ). + ( !empty( $sandbox ) ? "sandbox " . trim( $sandbox ) . "; " : "" ). + ( !empty( $default ) ? "default-src $default;" : "" ), "; " ); + + if ( !empty( $dir ) ) { + $rules .= " Header set Content-Security-Policy \"$dir\"\n"; + } + } + + $rules .= "\n"; + } + $rules .= W3TC_MARKER_END_BROWSERCACHE_CACHE . "\n"; return $rules; @@ -500,6 +594,89 @@ private function rules_cache_generate_nginx($config, $cdnftp = false) { $this->_rules_cache_generate_nginx_for_type($config, $rules, $extensions, $type); + $rules .= "fastcgi_param PHP_FLAG \"session.cookie_httponly=" . ( $config->get_boolean( 'browsercache.security.session.cookie_httponly' ) ? "on" : "off" ) . "\n" . + "session.cookie_secure=" . ( $config->get_boolean( 'browsercache.security.session.cookie_secure' ) ? "on" : "off" ) . "\n" . + "session.use_only_cookies=" . ( $config->get_boolean( 'browsercache.security.session.use_only_cookies' ) ? "on" : "off" ) . "\";"; + + if ( $config->get_boolean( 'browsercache.security.hsts' ) || + $config->get_boolean( 'browsercache.security.xfo' ) || + $config->get_boolean( 'browsercache.security.xss' ) || + $config->get_boolean( 'browsercache.security.xcto' ) || + $config->get_boolean( 'browsercache.security.pkp' ) || + $config->get_boolean( 'browsercache.security.csp' ) + ) { + $lifetime = $config->get_integer( 'browsercache.other.lifetime' ); + + if ( $config->get_boolean( 'browsercache.security.hsts' ) ) { + $dir = $config->get_string( 'browsercache.security.hsts.directive' ); + $rules .= "add_header Strict-Transport-Security \"max-age=$lifetime" . ( strpos( $dir,"inc" ) ? "; includeSubDomains" : "" ) . ( strpos( $dir, "pre" ) ? "; preload" : "" ) . "\";\n"; + } + + if ( $config->get_boolean( 'browsercache.security.xfo' ) ) { + $dir = $config->get_string( 'browsercache.security.xfo.directive' ); + $url = trim( $config->get_string( 'browsercache.security.xfo.allow' ) ); + if ( empty( $url ) ) { + $url = w3_get_url_ssl(w3_get_home_url()); + } + $rules .= "add_header X-Frame-Options \"" . ( $dir == "same" ? "SAMEORIGIN" : ( $dir == "deny" ? "DENY" : "ALLOW-FROM $url" ) ) . "\";\n"; + } + + if ( $config->get_boolean( 'browsercache.security.xss' ) ) { + $dir = $config->get_string( 'browsercache.security.xss.directive' ); + $rules .= "add_header X-XSS-Protection \"" . ( $dir == "block" ? "1; mode=block" : $dir ) . "\";\n"; + + } + + if ( $config->get_boolean( 'browsercache.security.xcto' ) ) { + $rules .= "add_header X-Content-Type-Options \"nosniff\";\n"; + } + + if ( $config->get_boolean( 'browsercache.security.pkp' ) ) { + $pin = trim( $config->get_string( 'browsercache.security.pkp.pin' ) ); + $pinbak = trim( $config->get_string( 'browsercache.security.pkp.pin.backup' ) ); + $extra = $config->get_string( 'browsercache.security.pkp.extra' ); + $url = trim( $config->get_string( 'browsercache.security.pkp.report.url' ) ); + $rep_only = $config->get_string( 'browsercache.security.pkp.report.only' ) == '1' ? true : false; + $rules .= "add_header " . ( $rep_only ? "Public-Key-Pins-Report-Only" : "Public-Key-Pins" ) . " 'pin-sha256=\"$pin\"; pin-sha256=\"$pinbak\"; max-age=$lifetime" . ( strpos( $extra,"inc" ) ? "; includeSubDomains" : "" ) . ( !empty( $url ) ? "; report-uri=\"$url\"" : "" ) . "';\n"; + } + + if ( $config->get_boolean( 'browsercache.security.csp' ) ) { + $base = trim( $config->get_string( 'browsercache.security.csp.base' ) ); + $frame = trim( $config->get_string( 'browsercache.security.csp.frame' ) ); + $connect = trim( $config->get_string( 'browsercache.security.csp.connect' ) ); + $font = trim( $config->get_string( 'browsercache.security.csp.font' ) ); + $script = trim( $config->get_string( 'browsercache.security.csp.script' ) ); + $style = trim( $config->get_string( 'browsercache.security.csp.style' ) ); + $img = trim( $config->get_string( 'browsercache.security.csp.img' ) ); + $media = trim( $config->get_string( 'browsercache.security.csp.media' ) ); + $object = trim( $config->get_string( 'browsercache.security.csp.object' ) ); + $plugin = trim( $config->get_string( 'browsercache.security.csp.plugin' ) ); + $form = trim( $config->get_string( 'browsercache.security.csp.form' ) ); + $frame_ancestors = trim( $config->get_string( 'browsercache.security.csp.frame.ancestors' ) ); + $sandbox = $config->get_string( 'browsercache.security.csp.sandbox' ); + $default = trim( $config->get_string( 'browsercache.security.csp.default' ) ); + + $dir = rtrim( ( !empty( $base ) ? "base-uri $base; " : "" ). + ( !empty( $frame ) ? "frame-src $frame; " : "" ). + ( !empty( $connect ) ? "connect-src $connect; " : "" ). + ( !empty( $font ) ? "font-src $font; " : "" ). + ( !empty( $script ) ? "script-src $script; " : "" ). + ( !empty( $style ) ? "style-src $style; " : "" ). + ( !empty( $img ) ? "img-src $img; " : "" ). + ( !empty( $media ) ? "media-src $media; " : "" ). + ( !empty( $object ) ? "object-src $object; " : "" ). + ( !empty( $plugin ) ? "plugin-types $plugin; " : "" ). + ( !empty( $form ) ? "form-action $form; " : "" ). + ( !empty( $frame_ancestors ) ? "frame-ancestors $frame_ancestors; " : "" ). + ( !empty( $sandbox ) ? "sandbox " . trim( $sandbox ) . "; " : "" ). + ( !empty( $default ) ? "default-src $default;" : "" ), "; " ); + + if ( !empty( $dir ) ) { + $rules .= "add_header Content-Security-Policy \"$dir\";\n"; + } + } + } + $rules .= W3TC_MARKER_END_BROWSERCACHE_CACHE . "\n"; return $rules; diff --git a/lib/W3/Cli.php b/lib/W3/Cli.php index 7f571fb..476e180 100644 --- a/lib/W3/Cli.php +++ b/lib/W3/Cli.php @@ -61,7 +61,7 @@ function flush($args = array() , $vars = array()) } catch(Exception $e) { - WP_CLI::error("Flushing the minify cache failed: $e"); + WP_CLI::error("Flushing the minify cache failed: ". $e->getMessage()); } WP_CLI::success(__('The minify cache has flushed successfully.', 'w3-total-cache')); @@ -75,7 +75,7 @@ function flush($args = array() , $vars = array()) } catch(Exception $e) { - WP_CLI::error("Flushing the object cache failed: $e"); + WP_CLI::error("Flushing the object cache failed: ". $e->getMessage()); } WP_CLI::success(__('The object cache has flushed successfully.', 'w3-total-cache')); @@ -95,7 +95,7 @@ function flush($args = array() , $vars = array()) } catch(Exception $e) { - WP_CLI::error("Flushing the page from cache failed: $e"); + WP_CLI::error("Flushing the page from cache failed: ". $e->getMessage()); } WP_CLI::success(__('The page has been flushed from cache successfully.', 'w3-total-cache')); @@ -121,7 +121,7 @@ function flush($args = array() , $vars = array()) } catch(Exception $e) { - WP_CLI::error("Flushing the page from cache failed: $e"); + WP_CLI::error("Flushing the page from cache failed: ". $e->getMessage()); } WP_CLI::success(__('The page has been flushed from cache successfully.', 'w3-total-cache')); @@ -144,7 +144,7 @@ function flush($args = array() , $vars = array()) } catch(Exception $e) { - WP_CLI::error("Flushing the page cache failed: $e"); + WP_CLI::error("Flushing the page cache failed: ". $e->getMessage()); } WP_CLI::success(__('The page cache has been flushed successfully.', 'w3-total-cache')); @@ -177,21 +177,17 @@ function flush($args = array() , $vars = array()) * * ## EXAMPLES * - * wp w3-total-cache prime - * Begin priming the page cache using the already defined interval, batch size, - * and sitemap url values as shown under W3TC's Cache Preload section. + * # Prime the page cache using settings held within the W3TC config. + * $ wp w3-total-cache prime * - * wp w3-total-cache prime stop - * If the page cache is currently being primed this will end that process. + * # Stop the currently active prime process. + * $ wp w3-total-cache prime stop * - * wp w3-total-cache prime --batch=2 --interval=30 - * Begin priming the page cache at the rate of 2 pages every 30 seconds using the - * sitemap url held within W3TC's Cache Preload > Sitemap URL box. + * # Prime the page cache (2 pages every 30 seconds). + * $ wp w3-total-cache prime --batch=2 --interval=30 * - * wp w3-total-cache prime --interval=30 --sitemap=http://domain.com/sitemap.xml - * Using the provided sitemap url, its pages are primed in batch sizes (as defined - * by W3TC's Performance > Page Cache > Cache Preload > Pages per Interval box) - * every 30 seconds until all pages within said sitemap is complete. + * # Prime the page cache every 30 seconds using the given sitemap. + * $ wp w3-total-cache prime --interval=30 --sitemap=http://site.com/sitemap.xml */ function prime($args = array() , $vars = array()) { @@ -242,7 +238,11 @@ function prime($args = array() , $vars = array()) $interval = $user_interval == - 1 ? $config->get_integer('pgcache.prime.interval') : $user_interval; $sitemap = empty($user_sitemap) ? $config->get_string('pgcache.prime.sitemap') : $user_sitemap; - if (($res = $w3_prime->prime_cli($limit, $interval, $sitemap, 0, true)) === false) + if ( empty( $sitemap ) ) + { + WP_CLI::error( __( "Prime page cache halted - Unable to load sitemap. A sitemap is needed to prime the page cache.", 'w3-total-cache' ) ); + } + elseif (($res = $w3_prime->prime_cli($limit, $interval, $sitemap, 0, true)) === false) { WP_CLI::warning('Page cache priming is already active.'); } @@ -255,7 +255,7 @@ function prime($args = array() , $vars = array()) } catch(Exception $e) { - WP_CLI::error("$e"); + WP_CLI::error($e->getMessage()); } } @@ -271,7 +271,7 @@ function querystring() } catch(Exception $e) { - WP_CLI::error(__('updating the query string failed. with error %s', 'w3-total-cache') , $e); + WP_CLI::error('updating the query string failed. with error '. $e->getMessage()); } WP_CLI::success(__('The query string was updated successfully.', 'w3-total-cache')); @@ -300,7 +300,7 @@ function cdn_purge($args = array()) } catch(Exception $e) { - WP_CLI::error(__('Files did not successfully purge with error %s', 'w3-total-cache') , $e); + WP_CLI::error('Files did not successfully purge with error '. $e->getMessage()); } WP_CLI::success(__('Files purged successfully.', 'w3-total-cache')); @@ -347,7 +347,7 @@ function apc_reload_files($args = array()) if (is_wp_error($result)) { - WP_CLI::error(__('Files did not successfully reload with error %s', 'w3-total-cache') , $result); + WP_CLI::error('Files did not successfully reload with error '.$result->get_error_message()); } else if ($result['response']['code'] != '200') { @@ -357,7 +357,7 @@ function apc_reload_files($args = array()) } catch(Exception $e) { - WP_CLI::error(__('Files did not successfully reload with error %s', 'w3-total-cache') , $e); + WP_CLI::error('Files did not successfully reload with error '.$e->getMessage()); } WP_CLI::success(__('Files reloaded successfully.', 'w3-total-cache')); @@ -404,7 +404,7 @@ function opcache_reload_files($args = array()) if (is_wp_error($result)) { - WP_CLI::error(__('Files did not successfully reload with error %s', 'w3-total-cache') , $result); + WP_CLI::error('Files did not successfully reload with error '.$result->get_error_message()); } else if ($result['response']['code'] != '200') { @@ -414,7 +414,7 @@ function opcache_reload_files($args = array()) } catch(Exception $e) { - WP_CLI::error(__('Files did not successfully reload with error %s', 'w3-total-cache') , $e); + WP_CLI::error('Files did not successfully reload with error ' .$e->getMessage()); } WP_CLI::success(__('Files reloaded successfully.', 'w3-total-cache')); @@ -461,7 +461,7 @@ function apc_delete_based_on_regex($args = array()) if (is_wp_error($result)) { - WP_CLI::error(__('Files did not successfully delete with error %s', 'w3-total-cache') , $result); + WP_CLI::error(__('Files did not successfully delete with error '.$result->get_error_message(), 'w3-total-cache')); } else if ($result['response']['code'] != '200') { @@ -471,7 +471,7 @@ function apc_delete_based_on_regex($args = array()) } catch(Exception $e) { - WP_CLI::error(__('Files did not successfully delete with error %s', 'w3-total-cache') , $e); + WP_CLI::error(__('Files did not successfully delete with error '.$e->getMessage(), 'w3-total-cache')); } WP_CLI::success(__('Files deleted successfully.', 'w3-total-cache')); @@ -517,7 +517,7 @@ function opcache_delete_based_on_regex($args = array()) if (is_wp_error($result)) { - WP_CLI::error(__('Files did not successfully delete with error %s', 'w3-total-cache') , $result); + WP_CLI::error(__('Files did not successfully delete with error '.$result->get_error_message(), 'w3-total-cache')); } else if ($result['response']['code'] != '200') { @@ -527,7 +527,7 @@ function opcache_delete_based_on_regex($args = array()) } catch(Exception $e) { - WP_CLI::error(__('Files did not successfully delete with error %s', 'w3-total-cache') , $e); + WP_CLI::error(__('Files did not successfully delete with error '.$e->getMessage(), 'w3-total-cache')); } WP_CLI::success(__('Files deleted successfully.', 'w3-total-cache')); @@ -545,7 +545,7 @@ function pgcache_cleanup() } catch(Exception $e) { - WP_CLI::error(__('PageCache Garbage cleanup did not start with error %s', 'w3-total-cache') , $e); + WP_CLI::error(__('PageCache Garbage cleanup did not start with error '.$e->getMessage(), 'w3-total-cache')); } WP_CLI::success(__('PageCache Garbage cleanup triggered successfully.', 'w3-total-cache')); diff --git a/lib/W3/ConfigKeys.php b/lib/W3/ConfigKeys.php index df3865e..18e12b5 100644 --- a/lib/W3/ConfigKeys.php +++ b/lib/W3/ConfigKeys.php @@ -1244,6 +1244,10 @@ 'type' => 'boolean', 'default' => false ), + 'cdn.admin.media_library' => array( + 'type' => 'boolean', + 'default' => false + ), 'cdncache.enabled' => array( 'type' => 'boolean', 'default' => false @@ -1400,7 +1404,134 @@ 'type' => 'array', 'default' => array() ), - + 'browsercache.security.session.cookie_httponly' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.session.cookie_secure' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.session.use_only_cookies' => array( + 'type' => 'boolean', + 'default' => true + ), + 'browsercache.security.hsts' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.hsts.directive' => array( + 'type' => 'string', + 'default' => 'maxage' + ), + 'browsercache.security.xfo' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.xfo.directive' => array( + 'type' => 'string', + 'default' => 'same' + ), + 'browsercache.security.xfo.allow' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.xss' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.xss.directive' => array( + 'type' => 'string', + 'default' => 'block' + ), + 'browsercache.security.xcto' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.pkp' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.pkp.pin' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.pkp.pin.backup' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.pkp.extra' => array( + 'type' => 'string', + 'default' => 'maxage' + ), + 'browsercache.security.pkp.report.url' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.pkp.report.only' => array( + 'type' => 'string', + 'default' => '0' + ), + 'browsercache.security.csp' => array( + 'type' => 'boolean', + 'default' => false + ), + 'browsercache.security.csp.base' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.frame' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.connect' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.font' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.script' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.style' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.img' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.media' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.object' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.plugin' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.form' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.frame.ancestors' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.sandbox' => array( + 'type' => 'string', + 'default' => '' + ), + 'browsercache.security.csp.default' => array( + 'type' => 'string', + 'default' => '' + ), 'mobile.enabled' => array( 'type' => 'boolean', 'default' => false diff --git a/lib/W3/PgCache.php b/lib/W3/PgCache.php index b368b9f..f816467 100644 --- a/lib/W3/PgCache.php +++ b/lib/W3/PgCache.php @@ -580,24 +580,25 @@ function _can_cache2(&$buffer) { return false; } - if (is_single() && !$this->_check_cache_exception()) { + if ( !$this->_check_cache_exception() && ( is_single() || is_page() ) ) { + if ( is_single() ) { + /** + * Don't cache pages associated with categories + */ + if ($this->_check_categories()) { + $this->cache_reject_reason = 'Page associated with a rejected category'; - /** - * Don't cache pages associated with categories - */ - if ($this->_check_categories()) { - $this->cache_reject_reason = 'Page associated with a rejected category'; - - return false; - } + return false; + } - /** - * Don't cache pages that use tags - */ - if ($this->_check_tags()) { - $this->cache_reject_reason = 'Page using a rejected tag'; + /** + * Don't cache pages that use tags + */ + if ($this->_check_tags()) { + $this->cache_reject_reason = 'Page using a rejected tag'; - return false; + return false; + } } /** diff --git a/lib/W3/Plugin/Cdn.php b/lib/W3/Plugin/Cdn.php index 35121fe..f27d9b6 100644 --- a/lib/W3/Plugin/Cdn.php +++ b/lib/W3/Plugin/Cdn.php @@ -34,6 +34,16 @@ function run() { $cdn_engine = $this->_config->get_string('cdn.engine'); + add_filter( 'wp_get_attachment_url', array( + &$this, + 'w3tc_attachment_url' + ), 0 ); + + add_filter( 'attachment_link', array( + &$this, + 'w3tc_attachment_url' + ), 0 ); + if (!w3_is_cdn_mirror($cdn_engine)) { add_action('delete_attachment', array( &$this, @@ -1018,5 +1028,40 @@ private function make_uploads_regexes($domain_url_regexp, $baseurl, $upload_info } return $regexps; } + + /** + * Adjusts attachment urls to cdn. This is for those who rely on + * wp_get_attachment_url() + * + * @param string $url the local url to modify + * @return string + */ + function w3tc_attachment_url( $url ) { + static $allowed_files = null; + + if ( ( defined( 'WP_ADMIN' ) && $this->_config->get_boolean( 'cdn.admin.media_library' ) ) || + ( $this->can_cdn() && $this->can_cdn2( $empty ) ) ) { + $url = trim( $url ); + + if ( !empty( $url ) ) { + if ( empty( $allowed_files ) ) { + $allowed_files = $this->get_files(); + } + + $parsed = parse_url( $url ); + $rel_url = ( isset( $parsed['path'] ) ? $parsed['path'] : '/' ) . + ( isset( $parsed['query'] ) ? '?' . $parsed['query'] : '' ); + + if ( in_array( ltrim( $rel_url, '/' ), $allowed_files ) ) { + $common = w3_instance('W3_Plugin_CdnCommon'); + $cdn = $common->get_cdn(); + $remote_path = $common->uri_to_cdn_uri( $rel_url ); + $url = $cdn->format_url( $remote_path ); + } + } + } + + return $url; + } } diff --git a/lib/W3/SharedPageUrls.php b/lib/W3/SharedPageUrls.php index c744078..4d5a7b8 100644 --- a/lib/W3/SharedPageUrls.php +++ b/lib/W3/SharedPageUrls.php @@ -108,7 +108,17 @@ private function get_older_pages($posts_page_uri, $limit_post_pages = 10) { function get_post_urls($post_id) { if (!isset($this->post_urls[$post_id])) { $full_urls = array(); - $post_link = get_permalink($post_id); + $post = get_post( $post_id ); + + // On the admin page when changing a post type to "Draft" or "Pending Review" + // the get_permalink() returns back in the form: http://foo.bar/?p=### + // even if the site's permalink setting is different (e.g. http://foo.bar/post-name/). + // When this happens the post can potentially not get flushed. + // Setting the "post_status" to empty forces get_permalink() to return + // the correct url for flushing. + + $post->post_status = ""; + $post_link = get_permalink( $post ); $post_uri = str_replace($this->domain_url, '', $post_link); $full_urls[] = $post_link; diff --git a/lib/W3/UI/Settings/BrowserCache.php b/lib/W3/UI/Settings/BrowserCache.php index 7529b35..59d16fd 100644 --- a/lib/W3/UI/Settings/BrowserCache.php +++ b/lib/W3/UI/Settings/BrowserCache.php @@ -38,7 +38,38 @@ protected function strings() { 'browsercache.other.w3tc' => __('Set W3 Total Cache header', 'w3-total-cache'), 'browsercache.other.compression' => __('Enable HTTP (gzip) compression', 'w3-total-cache'), 'browsercache.other.replace' => __('Prevent caching of objects after settings change', 'w3-total-cache'), - 'browsercache.other.nocookies' => __('Disable cookies for static files', 'w3-total-cache') + 'browsercache.other.nocookies' => __('Disable cookies for static files', 'w3-total-cache'), + 'browsercache.security.session.cookie_httponly' => __( 'Access session cookies through the HTTP protocol only', 'w3-total-cache' ), + 'browsercache.security.session.cookie_secure' => __( 'Send session cookies only to secure connections', 'w3-total-cache' ), + 'browsercache.security.session.use_only_cookies' => __( 'Use cookies to store session IDs in the user\'s browser', 'w3-total-cache' ), + 'browsercache.security.hsts' => __( 'HTTP Strict Transport Security policy', 'w3-total-cache' ), + 'browsercache.security.hsts.directive' => __( 'Directive:', 'w3-total-cache' ), + 'browsercache.security.xfo' => __( 'X-Frame-Options', 'w3-total-cache' ), + 'browsercache.security.xfo.directive' => __( 'Directive:', 'w3-total-cache' ), + 'browsercache.security.xss' => __( 'X-XSS-Protection', 'w3-total-cache' ), + 'browsercache.security.xss.directive' => __( 'Directive:', 'w3-total-cache' ), + 'browsercache.security.xcto' => __( 'X-Content-Type-Options', 'w3-total-cache' ), + 'browsercache.security.pkp' => __( 'HTTP Public Key Pinning', 'w3-total-cache' ), + 'browsercache.security.pkp.pin' => __( 'Public Key:', 'w3-total-cache' ), + 'browsercache.security.pkp.pin.backup' => __( 'Public Key (Backup):', 'w3-total-cache' ), + 'browsercache.security.pkp.extra' => __( 'Extra Parameters:', 'w3-total-cache' ), + 'browsercache.security.pkp.report.url' => __( 'Report URL:', 'w3-total-cache' ), + 'browsercache.security.pkp.report.only' => __( 'Report Mode Only:', 'w3-total-cache' ), + 'browsercache.security.csp' => __( 'Content Security Policy', 'w3-total-cache' ), + 'browsercache.security.csp.base' => __( 'base-uri:', 'w3-total-cache' ), + 'browsercache.security.csp.frame' => __( 'frame-src:', 'w3-total-cache' ), + 'browsercache.security.csp.connect' => __( 'connect-src:', 'w3-total-cache' ), + 'browsercache.security.csp.font' => __( 'font-src:', 'w3-total-cache' ), + 'browsercache.security.csp.script' => __( 'script-src:', 'w3-total-cache' ), + 'browsercache.security.csp.style' => __( 'style-src:', 'w3-total-cache' ), + 'browsercache.security.csp.img' => __( 'img-src:', 'w3-total-cache' ), + 'browsercache.security.csp.media' => __( 'media-src:', 'w3-total-cache' ), + 'browsercache.security.csp.object' => __( 'object-src:', 'w3-total-cache' ), + 'browsercache.security.csp.plugin' => __( 'plugin-types:', 'w3-total-cache' ), + 'browsercache.security.csp.form' => __( 'form-action:', 'w3-total-cache' ), + 'browsercache.security.csp.frame.ancestors' => __( 'frame-ancestors:', 'w3-total-cache' ), + 'browsercache.security.csp.sandbox' => __( 'sandbox:', 'w3-total-cache' ), + 'browsercache.security.csp.default' => __( 'default-src:', 'w3-total-cache' ) ) ); } diff --git a/lib/W3/UI/Settings/CDN.php b/lib/W3/UI/Settings/CDN.php index bf90e9a..6271cf2 100644 --- a/lib/W3/UI/Settings/CDN.php +++ b/lib/W3/UI/Settings/CDN.php @@ -20,6 +20,7 @@ protected function strings() { 'cdncache.enabled' => __('Enable mirroring of pages', 'w3-total-cache'), 'cdn.canonical_header' => __('Add canonical header', 'w3-total-cache'), 'cdn.reject.ssl' => __('Disable CDN on SSL pages', 'w3-total-cache'), + 'cdn.admin.media_library' => __( 'Use CDN links for the Media Library on admin pages', 'w3-total-cache' ), 'cdn.reject.logged_roles' => __('Disable CDN for the following roles', 'w3-total-cache'), 'cdn.reject.uri' => __('Disable CDN on the following pages:', 'w3-total-cache'), 'cdn.autoupload.enabled' => __('Export changed files automatically', 'w3-total-cache'), diff --git a/pub/css/options.css b/pub/css/options.css index 845da52..eaf418a 100644 --- a/pub/css/options.css +++ b/pub/css/options.css @@ -44,12 +44,16 @@ input.w3tc-error, textarea.w3tc-error { border: 1px solid #f99 } - .w3tc-status { padding: 5px; line-height:2.3 } +#browsercache_security_xfo_allow { + padding-top:0; + padding-bottom:4px; +} + #w3tc-help ul { float: left; width: 29%; @@ -555,3 +559,10 @@ only screen and ( min-resolution: 2dppx) { #edge-mode.updated p { line-height: 20px; } + +#w3tc_csp { + width: 872px; + height: 654px; + background: url("../img/cspref.png") center center no-repeat; + margin: auto; +} diff --git a/pub/img/cspref.png b/pub/img/cspref.png new file mode 100644 index 0000000000000000000000000000000000000000..4f8420097cbab1b341abbfbfebdcb48dba64ed8d GIT binary patch literal 48720 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 z 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 JB|@Kk{uk4D6!ZW9 literal 0 HcmV?d00001 diff --git a/pub/js/options.js b/pub/js/options.js index 692c3c2..b337aca 100644 --- a/pub/js/options.js +++ b/pub/js/options.js @@ -380,7 +380,7 @@ function w3tc_toggle2(name, dependent_ids) { var id = '#' + name, dependants = '', n; for (n = 0; n < dependent_ids.length; n++) dependants += (n > 0 ? ',' : '') + '#' + dependent_ids[n]; - + jQuery(dependants).click(function() { var total_checked = true; @@ -579,6 +579,75 @@ function w3tc_use_poll_zone(type, nonce) { }, 'json'); } +function w3tc_security_headers() { + var directive_description = + { + browsercache_security_hsts_directive: + { + maxage: 'The time, in seconds (as defined under the "Expires Header Lifetime" box of "Media & Other Files"), that the browser should remember that this site is only to be accessed using HTTPS. This only affects the site\'s main domain.', + maxagepre: 'The time, in seconds (as defined under the "Expires Header Lifetime" box of "Media & Other Files"), that the browser should remember that this site is only to be accessed using HTTPS with a request to be included in Chrome\'s HSTS preload list - a list of sites that are hardcoded into Chrome as being HTTPS only. This only affects the site\'s main domain.', + maxageinc: 'The time, in seconds (as defined under the "Expires Header Lifetime" box of "Media & Other Files"), that the browser should remember that this site is only to be accessed using HTTPS. This affects the site\'s subdomains as well.', + maxageincpre: 'The time, in seconds (as defined under the "Expires Header Lifetime" box of "Media & Other Files"), that the browser should remember that this site is only to be accessed using HTTPS with a request to be included in Chrome\'s HSTS preload list - a list of sites that are hardcoded into Chrome as being HTTPS only. This affects the site\'s subdomains as well.' + }, + browsercache_security_xfo_directive: + { + same: "The page can only be displayed in a frame on the same origin as the page itself.", + deny: "The page cannot be displayed in a frame, regardless of the site attempting to do so.", + allow: "The page can only be displayed in a frame on the specified URL." + }, + browsercache_security_xss_directive: + { + 0: "Disables XSS filtering.", + 1: "Enables XSS filtering (usually default in browsers). If a cross-site scripting attack is detected, the browser will sanitize the page (remove the unsafe parts).", + block: "Enables XSS filtering. Rather than sanitizing the page, the browser will prevent rendering of the page if an attack is detected." + }, + browsercache_security_pkp_extra: + { + maxage: 'The time, in seconds (as defined under the "Expires Header Lifetime" box of "Media & Other Files"), that the browser should remember that this site is only to be accessed using one of the defined keys. This only affects the site\'s main domain.', + maxageinc: 'The time, in seconds (as defined under the "Expires Header Lifetime" box of "Media & Other Files"), that the browser should remember that this site is only to be accessed using one of the defined keys. This affects the site\'s subdomains as well.' + }, + browsercache_security_pkp_report_only: + { + 0: 'This instructs the browser to enforce the HPKP policy.', + 1: 'This sets up HPKP without enforcement allowing you to use pinning to test its impact without the risk of a failed connection caused by your site being unreachable or HPKP being misconfigured.' + } + }; + + jQuery('#browsercache_security_hsts_directive,#browsercache_security_xfo_directive,#browsercache_security_xss_directive,#browsercache_security_pkp_extra,#browsercache_security_pkp_report_only').change( + function() { + jQuery('#' + jQuery(this).attr('id') + '_description').html('' + directive_description[jQuery(this).attr('id')][jQuery(this).val()] + ''); + if (jQuery(this).attr('id') == 'browsercache_security_xfo_directive') { + if (jQuery(this).val() == 'allow') { + jQuery('#browsercache_security_xfo_allow').show(); + }else { + jQuery('#browsercache_security_xfo_allow').hide(); + } + } + }); + + if(jQuery('#browsercache_security_xfo_allow').length) { + if (jQuery('#browsercache_security_xfo_directive').val() == 'allow') { + jQuery('#browsercache_security_xfo_allow').show(); + } else { + jQuery('#browsercache_security_xfo_allow').hide(); + } + jQuery('#browsercache_security_hsts_directive,#browsercache_security_xfo_directive,#browsercache_security_xss_directive,#browsercache_security_pkp_extra,#browsercache_security_pkp_report_only').change(); + } +} + +function w3tc_csp_reference() { + W3tc_Lightbox.open({ + id: 'w3tc-overlay', + close: '', + width: 890, + height: 660, + content: '
' + }); + jQuery('div#overlay,.lightbox-content').click(function() { + W3tc_Lightbox.close(); + }); +} + jQuery(function() { // general page w3tc_toggle('enabled'); @@ -754,6 +823,8 @@ jQuery(function() { w3tc_toggle2('browsercache_nocookies', ['browsercache_cssjs_nocookies', 'browsercache_other_nocookies']); + w3tc_security_headers(); + // minify page w3tc_input_enable('.html_enabled', jQuery('#minify_html_enable:checked').size()); w3tc_input_enable('.js_enabled', jQuery('#minify_js_enable:checked').size()); @@ -983,6 +1054,10 @@ jQuery(function() { w3tc_use_poll_zone(metadata.type, metadata.nonce); }); + jQuery('#cdn_s3_bucket,#cdn_cf_bucket').focusout(function () { + jQuery(this).val(jQuery(this).val().toLowerCase()); + }); + jQuery('#cdn_test').click(function() { var me = jQuery(this); var metadata = me.metadata(); @@ -1185,7 +1260,7 @@ jQuery(function() { status.removeClass('w3tc-error'); status.removeClass('w3tc-success'); status.addClass('w3tc-process'); - + var status2 = jQuery('#cdn_create_container_status'); status2.removeClass('w3tc-error'); status2.removeClass('w3tc-success'); @@ -1294,7 +1369,7 @@ jQuery(function() { var status2 = jQuery('#cdn_test_status'); status2.removeClass('w3tc-error'); status2.removeClass('w3tc-success'); - status2.html(''); + status2.html(''); status.html('Creating...'); diff --git a/readme.txt b/readme.txt index c1f37ed..551b281 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: fredericktownes Tags: w3totalcache, w3 totalcache, w3total cache, wpo, web performance optimization, performance, availability, scaling, scalability, user experience, cache, caching, page cache, css cache, js cache, db cache, disk cache, disk caching, database cache, http compression, gzip, deflate, minify, cdn, content delivery network, media library, performance, speed, multiple hosts, css, merge, combine, unobtrusive javascript, compress, optimize, optimizer, javascript, js, cascading style sheet, plugin, yslow, yui, google, google rank, google page speed, mod_pagespeed, new relic, newrelic, aws, s3, cloudfront, sns, elasticache, rds, flash media server, amazon web services, cloud files, rackspace, akamai, max cdn, limelight, cloudflare, mod_cloudflare, microsoft, microsoft azure, iis, nginx, litespeed, apache, varnish, xcache, apc, eacclerator, wincache, mysql, w3 total cache, batcache, wp cache, wp super cache, quick cache, wp minify, bwp-minify, buddypress Requires at least: 3.2 Tested up to: 4.7.1 -Stable tag: 0.9.4.6.2 +Stable tag: 0.9.4.6.3 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -747,6 +747,14 @@ Please reach out to all of these people and support their projects if you're so == Changelog == += 0.9.4.6.3 = +* Security Headers section added to Browser Cache -- X-Frame-Options, X-XSS-Protection, X-Content-Type-Options, HTTP Public Key Pinning, Content Security Policy, HTTP Strict Transport Security, and Session Cookies +* Checkbox under CDN to allow CDN URLs to be used for the Media Library when on admin pages +* Bug fix to Amazon Web Services (AWS) Cloudfront (origin pull) distributions +* Bug fix for page cache's categories, tags, author, and custom fields +* WP-CLI prime - tweak for sitemaps +* Bug fix to now allow flushing of a post/page's cache when changing from published to draft/pending review + = 0.9.4.6.2 = * Fixed a strict mode error specific to PHP 5.4/5.6 users * Configuration file loader adjustment to handle a case of someone going from v0.9.5.2+ to v0.9.4.x diff --git a/w3-total-cache-fixed.php b/w3-total-cache-fixed.php index fd6f833..0fc0a39 100644 --- a/w3-total-cache-fixed.php +++ b/w3-total-cache-fixed.php @@ -2,7 +2,7 @@ /* Plugin Name: W3 Total Cache (Fixed) Description: A community driven build of W3 Total Cache originally developed by @ftownes. The aim is to continuously incorporate fixes, improvements, and enhancements over the official Wordpress release of W3 Total Cache. -Version: 0.9.4.6.2 +Version: 0.9.4.6.3 Plugin URI: https://github.com/szepeviktor/w3-total-cache-fixed/ Author: W3TC (Fixed) Community Author URI: https://github.com/szepeviktor/w3-total-cache-fixed/