Merge pull request #3 from inputobjects/fixme/escape-at-last-step

Another Round of WordPress team feedback
This commit is contained in:
Jarek Rozanski 2021-12-31 10:06:13 +01:00 committed by GitHub
commit da8aa292f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 77 deletions

View file

@ -1,5 +1,5 @@
<?php <?php
class WideAngleConfig { class WideAngleAttributes {
public $siteId; public $siteId;
public $ignoreHash; public $ignoreHash;
public $trackerDomain; public $trackerDomain;
@ -16,34 +16,20 @@ class WideAngleConfig {
$this->helpers = new WideAngleHelpers(); $this->helpers = new WideAngleHelpers();
} }
function generateHeaderScript() { public function generateAttributes() {
$script = <<<EOD return array(
<link href="https://{$this->trackerDomain}/script/{$this->siteId}.js" ref="prefetch"/> 'site_id' => $this->siteId,
EOD; 'tracker_domain' => $this->trackerDomain,
return $script; 'ignore_hash' => $this->ignoreHash,
'exclusion_paths' => $this->generateExclusionsAttribute(),
'include_params' => $this->generateIncludeParamsAttribute()
);
} }
function generateFooterScript() {
$pathExlusionsAttribute = $this->generateExclusionsAttribute();
$includeParamsAttribute = $this->generateIncludeParamsAttribute();
$trackerUrlAttribute = esc_attr("https://{$this->trackerDomain}/script/{$this->siteId}.js");
$ignoreHashAttribute = esc_attr($this->ignoreHash);
$script = <<<EOD
<script async defer
src="{$trackerUrlAttribute}"
data-waa-ignore-hash="{$ignoreHashAttribute}"
$includeParamsAttribute
$pathExlusionsAttribute></script>
EOD;
return preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $script);
}
private function generateIncludeParamsAttribute() { private function generateIncludeParamsAttribute() {
$params = $this->helpers->parseIncludeParamsSetting($this->includeParamsString); $params = $this->helpers->parseIncludeParamsSetting($this->includeParamsString);
if(sizeof($params) > 0) { return implode(",", $params);
return "data-waa-inc-params=\"" . esc_attr(implode(",", $params)) . "\"";
}
return "";
} }
private function generateExclusionsAttribute() { private function generateExclusionsAttribute() {
@ -53,11 +39,7 @@ EOD;
$pathExlusionsAttribute = $this->generateExclusionsAttributeValue($exclusions); $pathExlusionsAttribute = $this->generateExclusionsAttributeValue($exclusions);
} }
$pathExlusionsAttributeWithKey = ""; return $pathExlusionsAttribute;
if(trim($pathExlusionsAttribute) != "") {
$pathExlusionsAttributeWithKey = "data-waa-exc-paths=\"" . esc_attr($pathExlusionsAttribute) ."\"";
}
return $pathExlusionsAttributeWithKey;
} }
private function generateExclusionsAttributeValue($exclusions) { private function generateExclusionsAttributeValue($exclusions) {

View file

@ -0,0 +1,44 @@
<?php
class WideAngleGenerator {
public $siteId;
public $ignoreHash;
public $trackerDomain;
public $exclusionPaths;
public $includeParams;
public function __construct($attributes) {
$this->siteId = $attributes['site_id'];
$this->trackerDomain = $attributes['tracker_domain'];
$this->ignoreHash = $attributes['ignore_hash'];
$this->exclusionPaths = $attributes['exclusion_paths'];
$this->includeParams = $attributes['include_params'];
}
function generateHeaderScript() {
$href = esc_attr("https://{$this->trackerDomain}/script/{$this->siteId}.js");
$script = <<<EOD
<link href="{$href}" ref="prefetch"/>
EOD;
return $script;
}
function generateFooterScript() {
$trackerUrlAttribute = esc_attr("https://{$this->trackerDomain}/script/{$this->siteId}.js");
$pathExlusionsAttribute = $this->exclusionPaths != '' ? "data-waa-exc-paths=\"" . esc_attr($this->exclusionPaths) . "\"": '';
$includeParamsAttribute = $this->includeParams != '' ? "data-waa-inc-params=\"" . esc_attr($this->includeParams) . "\"": '';
$ignoreHashAttribute = $this->ignoreHash != '' ? "data-waa-ignore-hash=\"" . esc_attr($this->ignoreHash) . "\"": 'data-waa-ignore-hash="false"';
$script = <<<EOD
<script async defer
src="{$trackerUrlAttribute}"
$ignoreHashAttribute
$includeParamsAttribute
$pathExlusionsAttribute></script>
EOD;
return preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\n", $script);
}
}
?>

View file

@ -50,10 +50,11 @@ class WideAngleHelpers {
$params = array(); $params = array();
foreach($request as $requestKey => $paramValue) { foreach($request as $requestKey => $paramValue) {
if(preg_match(self::includeParamRequestKeyPattern, $requestKey)) { if(preg_match(self::includeParamRequestKeyPattern, $requestKey)) {
if(preg_match(self::includeParamRequestValuePattern, $paramValue)) { $sanitizedValue = sanitize_text_field($paramValue);
array_push($params, trim($paramValue)); if(preg_match(self::includeParamRequestValuePattern, $sanitizedValue)) {
array_push($params, trim($sanitizedValue));
} else { } else {
return WideAngleValidated::createInvalid($name, $paramValue, "Name of parameter to include in request must consint of letters, numbers and can contain _ or - sign only."); return WideAngleValidated::createInvalid($name, $sanitizedValue, "Name of parameter to include in request must consint of letters, numbers and can contain _ or - sign only.");
} }
} }
} }
@ -67,13 +68,13 @@ class WideAngleHelpers {
$idx = array(); $idx = array();
if(preg_match(self::excludePathRequestKeyPattern, $key, $idx)) { if(preg_match(self::excludePathRequestKeyPattern, $key, $idx)) {
$valueKey = "waa_exc_path_".$idx[1]."_value"; $valueKey = "waa_exc_path_".$idx[1]."_value";
$exclusionValue = trim($request[$valueKey]); $sanitizedValue = trim(sanitize_text_field($request[$valueKey]));
if($exclusionValue != null) { if($sanitizedValue != null) {
if(filter_var($exclusionValue, FILTER_VALIDATE_REGEXP)) { if(filter_var($sanitizedValue, FILTER_VALIDATE_REGEXP)) {
$typedExclusion = "[" . $exclusionType . "]" . $exclusionValue; $typedExclusion = "[" . $exclusionType . "]" . $sanitizedValue;
array_push($exclusions, $typedExclusion); array_push($exclusions, $typedExclusion);
} else { } else {
$typedExclusion = "[" . $exclusionType . "]" . filter_var($exclusionValue, FILTER_SANITIZE_SPECIAL_CHARS); $typedExclusion = "[" . $exclusionType . "]" . filter_var($sanitizedValue, FILTER_SANITIZE_SPECIAL_CHARS);
array_push($exclusions, $typedExclusion); array_push($exclusions, $typedExclusion);
} }
} }

View file

@ -1,9 +1,10 @@
<?php <?php
$siteId = $this->settings[self::WAA_CONF_SITE_ID]; $siteId = wp_unslash($this->settings[self::WAA_CONF_SITE_ID]);
$trackerDomain = $this->settings[self::WAA_CONF_TRACKER_DOMAIN]; $trackerDomain = wp_unslash($this->settings[self::WAA_CONF_TRACKER_DOMAIN]);
$ignoreHash = filter_var($this->settings[self::WAA_CONF_IGNORE_HASH], FILTER_VALIDATE_BOOLEAN); $ignoreHash = filter_var($this->settings[self::WAA_CONF_IGNORE_HASH], FILTER_VALIDATE_BOOLEAN);
$parsedExclusions = $this->plugin->helpers->parseExclusionSetting($this->settings[self::WAA_CONF_EXC_PATHS]); $parsedExclusions = $this->plugin->helpers->parseExclusionSetting(wp_unslash($this->settings[self::WAA_CONF_EXC_PATHS]));
$parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this->settings[self::WAA_CONF_INC_PARAMS]); $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting(wp_unslash($this->settings[self::WAA_CONF_INC_PARAMS]));
$generator = new WideAngleGenerator($this->settings[self::WAA_CONF_ATTRIBUTES]);
?> ?>
<div class="wrap"> <div class="wrap">
<h2> <h2>
@ -136,11 +137,11 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this-
<pre style="padding: 1rem; border: 1px solid;"> <pre style="padding: 1rem; border: 1px solid;">
&lt;head&gt; &lt;head&gt;
&lt;!-- .. --&gt; &lt;!-- .. --&gt;
<b><?php echo esc_html($this->settings[self::WAA_CONF_GENERATED_HEADER_SCRIPT]); ?></b> <b><?php echo esc_html($generator->generateHeaderScript()); ?></b>
&lt;/head&gt; &lt;/head&gt;
&lt;!-- .. --&gt; &lt;!-- .. --&gt;
<b><?php echo esc_html($this->settings[self::WAA_CONF_GENERATED_FOOTER_SCRIPT]); ?></b> <b><?php echo esc_html($generator->generateFooterScript()); ?></b>
</pre> </pre>
</code> </code>
</div> </div>

View file

@ -20,8 +20,7 @@ class WideAngleAnalytics {
const WAA_CONF_EXC_PATHS = "waa_exc_path"; const WAA_CONF_EXC_PATHS = "waa_exc_path";
const WAA_CONF_INC_PARAMS = "waa_inc_params"; const WAA_CONF_INC_PARAMS = "waa_inc_params";
const WAA_CONF_IGNORE_HASH = "waa_ignore_hash"; const WAA_CONF_IGNORE_HASH = "waa_ignore_hash";
const WAA_CONF_GENERATED_HEADER_SCRIPT = "waa_header_script"; const WAA_CONF_ATTRIBUTES = "waa_attributes";
const WAA_CONF_GENERATED_FOOTER_SCRIPT = "waa_footer_script";
public function __construct() { public function __construct() {
$this->plugin = new stdClass; $this->plugin = new stdClass;
@ -29,6 +28,7 @@ class WideAngleAnalytics {
$this->plugin->displayName = 'Wide Angle Analytics'; $this->plugin->displayName = 'Wide Angle Analytics';
$this->plugin->folder = plugin_dir_path( __FILE__ ); $this->plugin->folder = plugin_dir_path( __FILE__ );
include_once( $this->plugin->folder . '/types/WideAngleHelpers.php' ); include_once( $this->plugin->folder . '/types/WideAngleHelpers.php' );
include_once( $this->plugin->folder . '/types/WideAngleGenerator.php' );
$this->plugin->helpers = new WideAngleHelpers(); $this->plugin->helpers = new WideAngleHelpers();
$this->plugin->exclusionTypes = array( $this->plugin->exclusionTypes = array(
@ -48,7 +48,8 @@ class WideAngleAnalytics {
* Inteded to be used with 'wp_head' hook. * Inteded to be used with 'wp_head' hook.
*/ */
function renderHeaderScript() { function renderHeaderScript() {
$this->renderSetting(self::WAA_CONF_GENERATED_HEADER_SCRIPT); $generator = new WideAngleGenerator(get_option(self::WAA_CONF_ATTRIBUTES));
$this->renderContent($generator->generateHeaderScript()); // The Escaping takes place in the WideAngleGenerator::generateHeaderScript method.
} }
/** /**
@ -56,14 +57,16 @@ class WideAngleAnalytics {
* Inteded to be used with 'wp_footer' hook. * Inteded to be used with 'wp_footer' hook.
*/ */
function renderFooterScript() { function renderFooterScript() {
$this->renderSetting(self::WAA_CONF_GENERATED_FOOTER_SCRIPT); $generator = new WideAngleGenerator(get_option(self::WAA_CONF_ATTRIBUTES));
$this->renderContent($generator->generateHeaderScript()); // The Escaping takes place in the WideAngleGenerator::generateHeaderScript method.
} }
/** /**
* When called, renders content of named setting. * Helper function to render provided content "as-is" when rendering public facing page.
* Rendering is omitted if current view is: Admin, Feed, Robots or Trackback. *
* The $content is already escaped.
*/ */
function renderSetting($setting) { private function renderContent($content) {
if ( if (
is_admin() || is_admin() ||
is_feed() || is_feed() ||
@ -71,12 +74,10 @@ class WideAngleAnalytics {
is_trackback()) { is_trackback()) {
return; return;
} }
if(trim($content) === "") {
$script = get_option($setting);
if(trim($script) === "") {
return; return;
} }
echo wp_unslash($script); echo wp_unslash($content);
} }
/** /**
@ -111,13 +112,13 @@ class WideAngleAnalytics {
} elseif ( ! wp_verify_nonce( $_REQUEST[ $this->plugin->name . '_nonce' ], $this->plugin->name ) ) { } elseif ( ! wp_verify_nonce( $_REQUEST[ $this->plugin->name . '_nonce' ], $this->plugin->name ) ) {
$this->errorMessage = __( 'Invalid nonce specified. Settings NOT saved.', $this->plugin->name ); $this->errorMessage = __( 'Invalid nonce specified. Settings NOT saved.', $this->plugin->name );
} else { } else {
$waaSiteId = $this->plugin->helpers->validateSiteId(self::WAA_CONF_SITE_ID, $_REQUEST['waa_site_id']); $waaSiteId = $this->plugin->helpers->validateSiteId(self::WAA_CONF_SITE_ID, sanitize_text_field($_REQUEST['waa_site_id']));
$waaTrackerDomain = $this->plugin->helpers->validateTrackerDomain(self::WAA_CONF_TRACKER_DOMAIN, $_REQUEST['waa_tracker_domain']); $waaTrackerDomain = $this->plugin->helpers->validateTrackerDomain(self::WAA_CONF_TRACKER_DOMAIN, sanitize_text_field($_REQUEST['waa_tracker_domain']));
$waaIgnoreHash = $this->plugin->helpers->validateIgnoreHashFlag(self::WAA_CONF_IGNORE_HASH, $_REQUEST['waa_ignore_hash']); $waaIgnoreHash = $this->plugin->helpers->validateIgnoreHashFlag(self::WAA_CONF_IGNORE_HASH, sanitize_text_field($_REQUEST['waa_ignore_hash']));
$waaIncParams = $this->plugin->helpers->validateIncludeParams(self::WAA_CONF_INC_PARAMS, $_REQUEST); $waaIncParams = $this->plugin->helpers->validateIncludeParams(self::WAA_CONF_INC_PARAMS, $_REQUEST);
$waaExclusionPaths = $this->plugin->helpers->validateExclusionPathsRequest(self::WAA_CONF_EXC_PATHS, $_REQUEST); $waaExclusionPaths = $this->plugin->helpers->validateExclusionPathsRequest(self::WAA_CONF_EXC_PATHS, $_REQUEST);
include_once( $this->plugin->folder . '/types/WideAngleConfig.php'); include_once( $this->plugin->folder . '/types/WideAngleAttributes.php');
$merged = array($waaSiteId, $waaTrackerDomain, $waaIgnoreHash, $waaIncParams, $waaExclusionPaths); $merged = array($waaSiteId, $waaTrackerDomain, $waaIgnoreHash, $waaIncParams, $waaExclusionPaths);
$errors = array(); $errors = array();
foreach($merged as $validated) { foreach($merged as $validated) {
@ -127,15 +128,14 @@ class WideAngleAnalytics {
} }
if(count($errors) === 0) { if(count($errors) === 0) {
$config = new WideAngleConfig($waaSiteId->get_value(), $waaTrackerDomain->get_value(), $waaIgnoreHash->get_value(), $waaExclusionPaths->get_value(), $waaIncParams->get_value()); $attributes = new WideAngleAttributes($waaSiteId->get_value(), $waaTrackerDomain->get_value(), $waaIgnoreHash->get_value(), $waaExclusionPaths->get_value(), $waaIncParams->get_value());
update_option(self::WAA_CONF_GENERATED_FOOTER_SCRIPT, $config->generateFooterScript()); update_option(self::WAA_CONF_SITE_ID, $waaSiteId->get_value());
update_option(self::WAA_CONF_GENERATED_HEADER_SCRIPT, $config->generateHeaderScript()); update_option(self::WAA_CONF_TRACKER_DOMAIN, $waaTrackerDomain->get_value());
update_option(self::WAA_CONF_SITE_ID, $waaSiteId->get_value()); update_option(self::WAA_CONF_IGNORE_HASH, $waaIgnoreHash->get_value());
update_option(self::WAA_CONF_TRACKER_DOMAIN, $waaTrackerDomain->get_value()); update_option(self::WAA_CONF_EXC_PATHS, $waaExclusionPaths->get_value());
update_option(self::WAA_CONF_IGNORE_HASH, $waaIgnoreHash->get_value()); update_option(self::WAA_CONF_INC_PARAMS, $waaIncParams->get_value());
update_option(self::WAA_CONF_EXC_PATHS, $waaExclusionPaths->get_value()); update_option(self::WAA_CONF_ATTRIBUTES, $attributes->generateAttributes());
update_option(self::WAA_CONF_INC_PARAMS, $waaIncParams->get_value());
$this->message = __('Settings updated', $this->plugin->name); $this->message = __('Settings updated', $this->plugin->name);
} else { } else {
$this->errorMessage = $errors; $this->errorMessage = $errors;
@ -143,13 +143,12 @@ class WideAngleAnalytics {
} }
} }
$this->settings = array( $this->settings = array(
self::WAA_CONF_SITE_ID => get_option( self::WAA_CONF_SITE_ID), self::WAA_CONF_SITE_ID => get_option(self::WAA_CONF_SITE_ID),
self::WAA_CONF_EXC_PATHS => get_option( self::WAA_CONF_EXC_PATHS), self::WAA_CONF_EXC_PATHS => get_option(self::WAA_CONF_EXC_PATHS),
self::WAA_CONF_INC_PARAMS => get_option( self::WAA_CONF_INC_PARAMS), self::WAA_CONF_INC_PARAMS => get_option(self::WAA_CONF_INC_PARAMS),
self::WAA_CONF_TRACKER_DOMAIN => get_option( self::WAA_CONF_TRACKER_DOMAIN), self::WAA_CONF_TRACKER_DOMAIN => get_option(self::WAA_CONF_TRACKER_DOMAIN),
self::WAA_CONF_IGNORE_HASH => get_option( self::WAA_CONF_IGNORE_HASH), self::WAA_CONF_IGNORE_HASH => get_option(self::WAA_CONF_IGNORE_HASH),
self::WAA_CONF_GENERATED_HEADER_SCRIPT => get_option( self::WAA_CONF_GENERATED_HEADER_SCRIPT), self::WAA_CONF_ATTRIBUTES => get_option(self::WAA_CONF_ATTRIBUTES)
self::WAA_CONF_GENERATED_FOOTER_SCRIPT => get_option( self::WAA_CONF_GENERATED_FOOTER_SCRIPT),
); );
include_once( $this->plugin->folder . '/views/admin_settings.php' ); include_once( $this->plugin->folder . '/views/admin_settings.php' );
} }
@ -172,8 +171,7 @@ class WideAngleAnalytics {
register_setting($this->plugin->name, self::WAA_CONF_INC_PARAMS); register_setting($this->plugin->name, self::WAA_CONF_INC_PARAMS);
register_setting($this->plugin->name, self::WAA_CONF_TRACKER_DOMAIN, array('default' => 'stats.wideangle.co')); register_setting($this->plugin->name, self::WAA_CONF_TRACKER_DOMAIN, array('default' => 'stats.wideangle.co'));
register_setting($this->plugin->name, self::WAA_CONF_IGNORE_HASH, array('default' => 'false')); register_setting($this->plugin->name, self::WAA_CONF_IGNORE_HASH, array('default' => 'false'));
register_setting($this->plugin->name, self::WAA_CONF_GENERATED_HEADER_SCRIPT); register_setting($this->plugin->name, self::WAA_CONF_ATTRIBUTES, array('type' => 'array'));
register_setting($this->plugin->name, self::WAA_CONF_GENERATED_FOOTER_SCRIPT);
} }
} }