From d90405d4501d99098a71f40433501bb6274caaea Mon Sep 17 00:00:00 2001 From: Jaroslaw Rozanski Date: Tue, 28 Dec 2021 23:57:28 +0100 Subject: [PATCH 1/4] Apply correct Version and Stable Tag so they match --- readme.txt | 2 +- wide-angle-analytics.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.txt b/readme.txt index f0ecf10..2ea964e 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: web analytics, tracking, web traffic, analytics Requires at least: 5.2 Tested up to: 5.8.2 Requires PHP: 7.2 -Stable tag: trunk +Stable tag: 1.0.1 License: GPLv2 Easily add Wide Angle Analytics tracker script to your WordPress site. You can quickly configure your web analytics tracker script. diff --git a/wide-angle-analytics.php b/wide-angle-analytics.php index ab6d725..14648e4 100644 --- a/wide-angle-analytics.php +++ b/wide-angle-analytics.php @@ -5,7 +5,7 @@ Description: Easily enable and configure Wide Angle Analytics on your Wordpress site Author: Wide Angle Analytics by Input Objects GmbH Author URI: https://wideangle.co - Version: 1.0.0 + Version: 1.0.1 Requires at least: 5.2 Requires PHP: 7.2 License: GPL v2 From 53b7ead960c08497c4139e0a48786de60a28fb1d Mon Sep 17 00:00:00 2001 From: Jaroslaw Rozanski Date: Wed, 29 Dec 2021 00:07:14 +0100 Subject: [PATCH 2/4] Escape input before render - Admin Wizard --- views/admin_settings.php | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/views/admin_settings.php b/views/admin_settings.php index b064019..010424d 100644 --- a/views/admin_settings.php +++ b/views/admin_settings.php @@ -7,7 +7,7 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this- ?>

- plugin->displayName; ?> » + plugin->displayName; ?> »

@@ -27,30 +27,30 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this- message ) ) { ?> -

message; ?>

+

message); ?>

errorMessage ) ) { ?> -

errorMessage; ?>

+

errorMessage); ?>

-
+ @@ -62,20 +62,20 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this- for($i = 0; $i < sizeof($parsedExclusions); $i++) { $exclusion = $parsedExclusions[$i]; ?> -
- plugin->exclusionTypes as $id => $label) { ?> - + - - + +
plugin->helpers->parseIncludeParamsSetting($this- for($i = 0; $i < sizeof($parsedIncludeParams); $i++) { $param = $parsedIncludeParams[$i]; ?> -
- - +
+ +
plugin->helpers->parseIncludeParamsSetting($this-
 <head>
 <!-- .. -->
-settings[self::WAA_CONF_GENERATED_HEADER_SCRIPT]; ?>
+settings[self::WAA_CONF_GENERATED_HEADER_SCRIPT]); ?>
 
 </head>
 <!-- .. -->
-settings[self::WAA_CONF_GENERATED_FOOTER_SCRIPT]; ?>
+settings[self::WAA_CONF_GENERATED_FOOTER_SCRIPT]); ?>
 
From cfbeaa927847e54593f30e64ab8b95c6e301ab4b Mon Sep 17 00:00:00 2001 From: Jaroslaw Rozanski Date: Wed, 29 Dec 2021 02:09:21 +0100 Subject: [PATCH 3/4] Validate User Input and report input errors --- types/WideAngleConfig.php | 4 +- types/WideAngleHelpers.php | 103 ++++++++++++++++++++++++------------- views/admin_settings.php | 17 ++++-- wide-angle-analytics.php | 89 +++++++++++++++----------------- 4 files changed, 123 insertions(+), 90 deletions(-) diff --git a/types/WideAngleConfig.php b/types/WideAngleConfig.php index 09d3106..7a74bc4 100644 --- a/types/WideAngleConfig.php +++ b/types/WideAngleConfig.php @@ -18,7 +18,7 @@ class WideAngleConfig { function generateHeaderScript() { $script = << + EOD; return $script; } @@ -29,7 +29,7 @@ EOD; $script = << diff --git a/types/WideAngleHelpers.php b/types/WideAngleHelpers.php index 606d6f2..891a174 100644 --- a/types/WideAngleHelpers.php +++ b/types/WideAngleHelpers.php @@ -1,9 +1,12 @@ plugin->folder . '/types/WideAngleExclusion.php' ); +include_once( $this->plugin->folder . '/types/WideAngleValidated.php' ); class WideAngleHelpers { - - + const WAA_SEPARTOR = "|:"; + private const includeParamRequestKeyPattern = "/^waa_inc_params_(\d{1,2})$/"; + private const includeParamRequestValuePattern = "/^[A-Za-z0-9_-]{1,128}$/"; + private const excludePathRequestKeyPattern = "/^waa_exc_path_(\d{1,2})_type$/"; function normalizeBoolean($value) { $trimmed = trim($value); @@ -18,8 +21,65 @@ class WideAngleHelpers { } } - function normalizeTrackerDomain($domain) { - return "https://" . parse_url($domain, PHP_URL_HOST); + function validateIgnoreHashFlag($name, $ignoreHash) { + if(filter_var($ignoreHash, FILTER_VALIDATE_BOOLEAN)) { + return WideAngleValidated::createValid($name, $ignoreHash, "true"); + } else { + return WideAngleValidated::createValid($name, $ignoreHash, "false"); + } + } + + function validateSiteId($name, $siteId) { + if(preg_match("/^[a-zA-Z0-9]{10,24}$/", $siteId)) { + return WideAngleValidated::createValid($name, $siteId, strtoupper(trim($siteId))); + } else { + return WideAngleValidated::createInvalid($name, $siteId, "Site ID is expected to consist only letters and digits. It must be at least 10 character long and no longer than 24."); + } + } + + function validateTrackerDomain($name, $domain) { + if(filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)) { + return WideAngleValidated::createValid($name, $domain, $domain); + } else { + return WideAngleValidated::createInvalid($name, $domain, "The tracked domain must be a valid domain name."); + } + } + + + function validateIncludeParams($name, $request) { + $params = array(); + foreach($request as $requestKey => $paramValue) { + if(preg_match(self::includeParamRequestKeyPattern, $requestKey)) { + if(preg_match(self::includeParamRequestValuePattern, $paramValue)) { + array_push($params, trim($paramValue)); + } 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::createValid($name, $params, implode(self::WAA_SEPARTOR, $params)); + } + + + function validateExclusionPathsRequest($name, $request) { + $exclusions = array(); + foreach($request as $key => $exclusionType) { + $idx = array(); + if(preg_match(self::excludePathRequestKeyPattern, $key, $idx)) { + $valueKey = "waa_exc_path_".$idx[1]."_value"; + $exclusionValue = trim($request[$valueKey]); + if($exclusionValue != null) { + if(filter_var($exclusionValue, FILTER_VALIDATE_REGEXP)) { + $typedExclusion = "[" . $exclusionType . "]" . $exclusionValue; + array_push($exclusions, $typedExclusion); + } else { + $typedExclusion = "[" . $exclusionType . "]" . filter_var($exclusionValue, FILTER_SANITIZE_SPECIAL_CHARS); + array_push($exclusions, $typedExclusion); + } + } + } + } + return WideAngleValidated::createValid($name, implode(self::WAA_SEPARTOR, $exclusions), null); } function parseIncludeParamsSetting($params) { @@ -30,23 +90,12 @@ class WideAngleHelpers { } } - function parseRequestIncludeParams($request) { - $pattern = "/^waa_inc_params_(\d{1,2})$/"; - $params = array(); - foreach($request as $key => $value) { - if(preg_match($pattern, $key)) { - array_push($params, trim($value)); - } - } - return $params; - } - function parseExclusionSetting($path) { $flatExclusions = $path; - $exclusions = preg_split("/\|\:/", $flatExclusions); - $exclusionPattern = '/^\[([A-Za-z0-9]{1,10})\](.*)$/'; - $matches = array(); - $parsedExclusions = array(); + $exclusions = preg_split("/\|\:/", $flatExclusions); + $exclusionPattern = '/^\[([A-Za-z0-9]{1,10})\](.*)$/'; + $matches = array(); + $parsedExclusions = array(); foreach($exclusions as $exclusion) { @@ -57,22 +106,6 @@ class WideAngleHelpers { return $parsedExclusions; } - function parseRequestExclusionPaths($request) { - $pattern = "/^waa_exc_path_(\d{1,2})_type$/"; - $exclusions = array(); - foreach($request as $key => $exclusionType) { - $idx = array(); - if(preg_match($pattern, $key, $idx)) { - $valueKey = "waa_exc_path_".$idx[1]."_value"; - $exclusionValue = trim($request[$valueKey]); - if($exclusionValue != null && $exclusionValue != "") { - $typedExclusion = "[" . $exclusionType . "]" .$exclusionValue; - array_push($exclusions, $typedExclusion); - } - } - } - return $exclusions; - } } ?> \ No newline at end of file diff --git a/views/admin_settings.php b/views/admin_settings.php index 010424d..86366cd 100644 --- a/views/admin_settings.php +++ b/views/admin_settings.php @@ -31,9 +31,18 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this- errorMessage ) ) { + if(is_array($this->errorMessage)) { + foreach($this->errorMessage as $error) { + ?> +

+

errorMessage); ?>

@@ -43,14 +52,14 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this-
@@ -71,8 +80,6 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this- - - @@ -94,7 +101,7 @@ $parsedIncludeParams = $this->plugin->helpers->parseIncludeParamsSetting($this- $param = $parsedIncludeParams[$i]; ?>
- +
plugin->name . '_nonce' ], $this->plugin->name ) ) { $this->errorMessage = __( 'Invalid nonce specified. Settings NOT saved.', $this->plugin->name ); } else { - $waaSiteId = $_REQUEST['waa_site_id']; - $waaTrackerDomain = $this->plugin->helpers->normalizeTrackerDomain(trim($_REQUEST['waa_tracker_domain'])); - $waaIgnoreHash = $this->plugin->helpers->normalizeBoolean($_REQUEST['waa_ignore_hash']); - $waaExclusionPaths = implode(self::WAA_SEPARTOR, $this->plugin->helpers->parseRequestExclusionPaths($_REQUEST)); - $waaIncParams = implode(self::WAA_SEPARTOR, $this->plugin->helpers->parseRequestIncludeParams($_REQUEST)); + $waaSiteId = $this->plugin->helpers->validateSiteId(self::WAA_CONF_SITE_ID, $_REQUEST['waa_site_id']); + $waaTrackerDomain = $this->plugin->helpers->validateTrackerDomain(self::WAA_CONF_TRACKER_DOMAIN, $_REQUEST['waa_tracker_domain']); + $waaIgnoreHash = $this->plugin->helpers->validateIgnoreHashFlag(self::WAA_CONF_IGNORE_HASH, $_REQUEST['waa_ignore_hash']); + $waaIncParams = $this->plugin->helpers->validateIncludeParams(self::WAA_CONF_INC_PARAMS, $_REQUEST); + $waaExclusionPaths = $this->plugin->helpers->validateExclusionPathsRequest(self::WAA_CONF_EXC_PATHS, $_REQUEST); - include_once( $this->plugin->folder . '/types/WideAngleConfig.php' ); - $config = new WideAngleConfig($waaSiteId, $waaTrackerDomain, $waaIgnoreHash, $waaExclusionPaths, $waaIncParams); + include_once( $this->plugin->folder . '/types/WideAngleConfig.php'); + $merged = array($waaSiteId, $waaTrackerDomain, $waaIgnoreHash, $waaIncParams, $waaExclusionPaths); + $errors = array(); + foreach($merged as $validated) { + if(!$validated->is_valid()) { + array_push($errors, $validated->get_error()); + } + } - update_option(self::WAA_CONF_GENERATED_FOOTER_SCRIPT, $config->generateFooterScript()); - update_option(self::WAA_CONF_GENERATED_HEADER_SCRIPT, $config->generateHeaderScript()); - update_option(self::WAA_CONF_SITE_ID, $waaSiteId ); - update_option(self::WAA_CONF_TRACKER_DOMAIN, $waaTrackerDomain); - update_option(self::WAA_CONF_IGNORE_HASH, $waaIgnoreHash ); - update_option(self::WAA_CONF_EXC_PATHS, $waaExclusionPaths ); - update_option(self::WAA_CONF_INC_PARAMS, $waaIncParams); + if(count($errors) === 0) { + $config = new WideAngleConfig($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_GENERATED_HEADER_SCRIPT, $config->generateHeaderScript()); + update_option(self::WAA_CONF_SITE_ID, $waaSiteId->get_value()); + update_option(self::WAA_CONF_TRACKER_DOMAIN, $waaTrackerDomain->get_value()); + update_option(self::WAA_CONF_IGNORE_HASH, $waaIgnoreHash->get_value()); + update_option(self::WAA_CONF_EXC_PATHS, $waaExclusionPaths->get_value()); + update_option(self::WAA_CONF_INC_PARAMS, $waaIncParams->get_value()); + $this->message = __('Settings updated', $this->plugin->name); + } else { + $this->errorMessage = $errors; + } } } $this->settings = array( - self::WAA_CONF_SITE_ID => esc_html(get_option( self::WAA_CONF_SITE_ID)), - self::WAA_CONF_EXC_PATHS => esc_html(get_option( self::WAA_CONF_EXC_PATHS)), - self::WAA_CONF_INC_PARAMS => esc_html(get_option( self::WAA_CONF_INC_PARAMS)), - self::WAA_CONF_TRACKER_DOMAIN => esc_html(get_option( self::WAA_CONF_TRACKER_DOMAIN)), - self::WAA_CONF_IGNORE_HASH => esc_html(get_option( self::WAA_CONF_IGNORE_HASH)), - self::WAA_CONF_GENERATED_HEADER_SCRIPT => esc_html(get_option( self::WAA_CONF_GENERATED_HEADER_SCRIPT )), - self::WAA_CONF_GENERATED_FOOTER_SCRIPT => esc_html(get_option( self::WAA_CONF_GENERATED_FOOTER_SCRIPT )), + 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_INC_PARAMS => get_option( self::WAA_CONF_INC_PARAMS), + 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_GENERATED_HEADER_SCRIPT => get_option( self::WAA_CONF_GENERATED_HEADER_SCRIPT), + self::WAA_CONF_GENERATED_FOOTER_SCRIPT => get_option( self::WAA_CONF_GENERATED_FOOTER_SCRIPT), ); include_once( $this->plugin->folder . '/views/admin_settings.php' ); } @@ -155,32 +167,13 @@ class WideAngleAnalytics { * - waa_footer_script */ function registerPluginSettings() { - register_setting( $this->plugin->name, self::WAA_CONF_SITE_ID, array( - 'sanitize_callback' => 'trim', - ) ); - register_setting( $this->plugin->name, self::WAA_CONF_EXC_PATHS, array( - 'sanitize_callback' => 'trim', - ) ); - register_setting( $this->plugin->name, self::WAA_CONF_INC_PARAMS, array( - 'sanitize_callback' =>'trim', - 'default' => '' - ) ); - register_setting( $this->plugin->name, self::WAA_CONF_TRACKER_DOMAIN, array( - 'sanitize_callback' => array(&$this->plugin->helpers, 'normalizeTrackerDomain'), - 'default' => 'https://stats.wideangle.co' - ) ); - register_setting( $this->plugin->name, self::WAA_CONF_IGNORE_HASH, array( - 'sanitize_callback' => array(&$this->plugin->helpers, 'normalizeBoolean'), - 'default' => 'false' - ) ); - register_setting( $this->plugin->name, self::WAA_CONF_GENERATED_HEADER_SCRIPT, array( - 'sanitize_callback' => 'trim', - 'default' => '' - ) ); - register_setting( $this->plugin->name, self::WAA_CONF_GENERATED_FOOTER_SCRIPT, array( - 'sanitize_callback' => 'trim', - 'default' => '' - ) ); + register_setting($this->plugin->name, self::WAA_CONF_SITE_ID); + register_setting($this->plugin->name, self::WAA_CONF_EXC_PATHS); + 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_IGNORE_HASH, array('default' => 'false')); + register_setting($this->plugin->name, self::WAA_CONF_GENERATED_HEADER_SCRIPT); + register_setting($this->plugin->name, self::WAA_CONF_GENERATED_FOOTER_SCRIPT); } } From a5ba22b56241c8fd044d9d15a1158ad677c8ffc4 Mon Sep 17 00:00:00 2001 From: Jaroslaw Rozanski Date: Wed, 29 Dec 2021 02:09:28 +0100 Subject: [PATCH 4/4] Validate User Input and report input errors --- types/WideAngleValidated.php | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 types/WideAngleValidated.php diff --git a/types/WideAngleValidated.php b/types/WideAngleValidated.php new file mode 100644 index 0000000..80f7487 --- /dev/null +++ b/types/WideAngleValidated.php @@ -0,0 +1,49 @@ +name = $name; + $this->value = $value; + $this->normalized = $normalized; + $this->error = $error; + $this->isValid = $isValid; + } + + public static function createValid($name, $value, $normalized) { + return new self($name, $value, $normalized, null, true); + } + + public static function createInvalid($name, $value, $error) { + return new self($name, $value, null, $error, false); + } + + public function get_name() { + return $this->name; + } + + public function get_value() { + if($this->normalized !== null) { + return $this->normalized; + } + return $this->value; + } + + public function get_error() { + if(!$this->isValid) { + return $this->error; + } + return null; + } + + public function is_valid() { + return $this->isValid; + } + +} +?> \ No newline at end of file