Changeset 3759933
- Timestamp:
- 10/22/2026 12:53:32 PM (3 weeks ago)
- Location:
- contact-form-by-supsystic
- Files:
-
- 2 added
- 34 edited
- 1 copied
-
tags/1.11.1 (copied) (copied from contact-form-by-supsystic/trunk )
-
tags/1.11.1/cfs.php (modified) (1 diff)
-
tags/1.11.1/classes/controller.php (modified) (5 diffs)
-
tags/1.11.1/classes/frame.php (modified) (4 diffs)
-
tags/1.11.1/classes/twigSecurityPolicy.php (added)
-
tags/1.11.1/classes/utils.php (modified) (1 diff)
-
tags/1.11.1/config.php (modified) (1 diff)
-
tags/1.11.1/js/core.js (modified) (2 diffs)
-
tags/1.11.1/js/core.min.js (modified) (1 diff)
-
tags/1.11.1/modules/forms/controller.php (modified) (1 diff)
-
tags/1.11.1/modules/forms/models/forms.php (modified) (6 diffs)
-
tags/1.11.1/modules/forms/views/forms.php (modified) (11 diffs)
-
tags/1.11.1/modules/forms/views/tpl/formsEditFormStatistics.php (modified) (1 diff)
-
tags/1.11.1/modules/mail/mod.php (modified) (2 diffs)
-
tags/1.11.1/modules/mail/views/tpl/mailAdmin.php (modified) (2 diffs)
-
tags/1.11.1/modules/options/models/options.php (modified) (3 diffs)
-
tags/1.11.1/modules/statistics/controller.php (modified) (1 diff)
-
tags/1.11.1/modules/templates/mod.php (modified) (1 diff)
-
tags/1.11.1/readme.txt (modified) (2 diffs)
-
trunk/cfs.php (modified) (1 diff)
-
trunk/classes/controller.php (modified) (5 diffs)
-
trunk/classes/frame.php (modified) (4 diffs)
-
trunk/classes/twigSecurityPolicy.php (added)
-
trunk/classes/utils.php (modified) (1 diff)
-
trunk/config.php (modified) (1 diff)
-
trunk/js/core.js (modified) (2 diffs)
-
trunk/js/core.min.js (modified) (1 diff)
-
trunk/modules/forms/controller.php (modified) (1 diff)
-
trunk/modules/forms/models/forms.php (modified) (6 diffs)
-
trunk/modules/forms/views/forms.php (modified) (11 diffs)
-
trunk/modules/forms/views/tpl/formsEditFormStatistics.php (modified) (1 diff)
-
trunk/modules/mail/mod.php (modified) (2 diffs)
-
trunk/modules/mail/views/tpl/mailAdmin.php (modified) (2 diffs)
-
trunk/modules/options/models/options.php (modified) (3 diffs)
-
trunk/modules/statistics/controller.php (modified) (1 diff)
-
trunk/modules/templates/mod.php (modified) (1 diff)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
contact-form-by-supsystic/tags/1.11.1/cfs.php
r3750257 r3759933 5 5 * Plugin URI: https://supsystic.com/plugins/contact-form-plugin/ 6 6 * Description: Drag-and-drop contact form builder with ready templates, 25+ field types, reCAPTCHA, saved submissions and form statistics. No coding needed. 7 * Version: 1.1 0.77 * Version: 1.11.1 8 8 * Author: supsystic.com 9 9 * Author URI: https://supsystic.com -
contact-form-by-supsystic/tags/1.11.1/classes/controller.php
r3679442 r3759933 104 104 public function __call($name, $arguments) 105 105 { 106 // delete()/clear() wipe the entire table when called with no/null arguments, 107 // which is exactly how they get invoked here (AJAX dispatch never actually 108 // passes $arguments through). Neither is reliably listed in every controller's 109 // getPermissions(), and havePermissions() defaults to "allow" for any action 110 // name it doesn't recognize - so without this check, any visitor could delete 111 // all data in a table simply by requesting action=delete or action=clear. 106 // delete()/clear() wipe the entire table when called with no/null arguments. 107 // Request dispatcher never routes actions here (frameCfs::havePermissions() accepts 108 // only real declared controller methods), but keep this guard for any other caller. 112 109 if (in_array(strtolower($name), ['delete', 'clear'], true)) { 113 110 return false; … … 136 133 ); 137 134 * Can be used on of sub-array - CFS_METHODS or CFS_USERLEVELS 135 * Methods that are not listed here and not listed in getPublicMethods() can not be called by request at all. 138 136 */ 139 137 public function getPermissions() … … 142 140 } 143 141 /** 144 * Methods that require nonce to be generated 142 * Methods that can be called by request from any visitor, including not logged in users. 143 * Each of them must validate request on it's own (own nonce, hash, etc.). 145 144 * If need - should be redefined in each controller where it required. 146 145 * @return array 147 146 */ 147 public function getPublicMethods() 148 { 149 return []; 150 } 151 /** 152 * Methods from getPermissions() that are opened by direct links from outside of plugin pages 153 * (for example - OAuth callbacks), so they can not carry plugin nonce. 154 * All other methods from getPermissions() always require valid plugin nonce. 155 * @return array 156 */ 157 public function getNonceExemptMethods() 158 { 159 return []; 160 } 161 /** 162 * Public methods that require plugin nonce too. 163 * Methods from getPermissions() require it anyway, @see frameCfs::havePermissions(). 164 * @return array 165 */ 148 166 public function getNoncedMethods() 149 167 { 150 168 return []; 169 } 170 /** 171 * Check that current request was sent by plugin administrator from plugin pages 172 * @return bool 173 */ 174 protected function _isAdminRequest() 175 { 176 return frameCfs::_()->getModule('user')->isAdmin() && frameCfs::_()->verifyNonce(); 151 177 } 152 178 public function getModule() … … 234 260 { 235 261 $res = new responseCfs(); 236 if ($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) { 262 // Inherited by all controllers - so check access here too, not only in request dispatcher 263 if (!$this->_isAdminRequest()) { 264 $res->pushError(__('You have no permissions to do this', CFS_LANG_CODE)); 265 } elseif ($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) { 237 266 $res->addMessage(__('Done', CFS_LANG_CODE)); 238 267 } else { … … 244 273 { 245 274 $res = new responseCfs(); 246 if ($this->getModel()->clear()) { 275 if (!$this->_isAdminRequest()) { 276 $res->pushError(__('You have no permissions to do this', CFS_LANG_CODE)); 277 } elseif ($this->getModel()->clear()) { 247 278 $res->addMessage(__('Done', CFS_LANG_CODE)); 248 279 } else { -
contact-form-by-supsystic/tags/1.11.1/classes/frame.php
r3641551 r3759933 23 23 private $_mod = ''; 24 24 private $_action = ''; 25 /** 26 * PRO before 1.5.0 does not declare it's public and nonce exempt methods, @see _isLegacyPro() 27 */ 28 private static $_legacyProPublicMethods = [ 29 'add_fields' => ['uploadFile', 'getFile', 'removeFile'], 30 'wp_subscribe' => ['confirm'], 31 ]; 32 private static $_legacyProNonceExemptMethods = [ 33 'campaignmonitor' => ['saveAccessToken'], 34 'constantcontact' => ['saveAccessToken'], 35 'verticalresponse' => ['saveAccessToken'], 36 // Read only exports - old PRO opens them by links without nonce 37 'ab_testing' => ['getListForTbl'], 38 'wp_subscribe' => ['getWpCsvList'], 39 'statistics' => ['getCsv'], 40 ]; 41 private static $_legacyPro = null; 25 42 /** 26 43 * Object with result of executing non-ajax module request … … 194 211 } 195 212 /** 196 * Check permissions for action in controller by $code 213 * Check permissions for action in controller by $code. 214 * Access is denied by default: an action can be dispatched only if its controller declares it, 215 * either as public (getPublicMethods() - such method must validate the request on its own), 216 * or for some user level (getPermissions()). Every action that is not public requires 217 * a valid plugin nonce too, except actions from getNonceExemptMethods(). 197 218 * @param string $code Code of controller that need to be checked 198 219 * @param string $action Action that need to be checked … … 201 222 public function havePermissions($code, $action) 202 223 { 203 $res = true; 224 $controller = $this->_getDispatchController($code, $action); 225 if (!$controller) { 226 return false; 227 } 228 $action = strtolower($action); 229 if ($this->_methodListed($action, $this->_getPublicMethods($code, $controller))) { 230 // Public methods can be additionally enrolled for the plugin nonce 231 return !$this->_methodListed($action, $controller->getNoncedMethods()) || $this->verifyNonce(); 232 } 233 $requiredLevels = $this->_getRequiredUserLevels($controller->getPermissions(), $action); 234 if (empty($requiredLevels)) { 235 // Action was not declared by controller - deny it 236 return false; 237 } 238 $currentUserPosition = $this->getModule('user')->getCurrentUserPosition(); 239 // For multi-sites network admin role is undefined, let's do this here 240 if (is_multisite() && is_admin() && is_super_admin()) { 241 $currentUserPosition = CFS_ADMIN; 242 } 243 foreach ($requiredLevels as $levels) { 244 if (!in_array($currentUserPosition, $levels, true)) { 245 return false; 246 } 247 } 248 if (!$this->_methodListed($action, $this->_getNonceExemptMethods($code, $controller)) && !$this->verifyNonce()) { 249 return false; 250 } 251 return true; 252 } 253 /** 254 * PRO add-on can be older than this plugin: before 1.5.0 it did not declare access for it's methods 255 * @return bool 256 */ 257 protected function _isLegacyPro() 258 { 259 if (self::$_legacyPro === null) { 260 self::$_legacyPro = function_exists('getProPlugCodeCfs') && !defined('CFS_PRO_DECLARES_ACCESS'); 261 } 262 return self::$_legacyPro; 263 } 264 protected function _getPublicMethods($code, $controller) 265 { 266 $methods = (array) $controller->getPublicMethods(); 267 if ($this->_isLegacyPro() && isset(self::$_legacyProPublicMethods[$code])) { 268 $methods = array_merge($methods, self::$_legacyProPublicMethods[$code]); 269 } 270 return $methods; 271 } 272 protected function _getNonceExemptMethods($code, $controller) 273 { 274 $methods = (array) $controller->getNonceExemptMethods(); 275 if ($this->_isLegacyPro() && isset(self::$_legacyProNonceExemptMethods[$code])) { 276 $methods = array_merge($methods, self::$_legacyProNonceExemptMethods[$code]); 277 } 278 return $methods; 279 } 280 /** 281 * Check if action is allowed for any visitor, including not logged in users 282 * @param string $code Code of controller that need to be checked 283 * @param string $action Action that need to be checked 284 * @return bool 285 */ 286 public function isPublicAction($code, $action) 287 { 288 $controller = $this->_getDispatchController($code, $action); 289 return $controller && $this->_methodListed(strtolower($action), $this->_getPublicMethods($code, $controller)); 290 } 291 /** 292 * Verify plugin nonce from current request 293 * @return bool 294 */ 295 public function verifyNonce() 296 { 297 $nonce = isset($_REQUEST['_wpnonce']) && is_string($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : ''; 298 if (empty($nonce)) { 299 return false; 300 } 301 return wp_verify_nonce($nonce, 'cfs_nonce') || wp_verify_nonce($nonce, 'cfs_nonce_frontend'); 302 } 303 /** 304 * Get controller of module, if action can be dispatched to it: it should be real public controller method, 305 * not some name that will be routed through controllerCfs::__call() to it's model. 306 * @param string $code Module code 307 * @param string $action Action name 308 * @return controllerCfs|null 309 */ 310 protected function _getDispatchController($code, $action) 311 { 204 312 $mod = $this->getModule($code); 205 $action = strtolower($action); 206 if ($mod) { 207 $permissions = $mod->getController()->getPermissions(); 208 if (!empty($permissions)) { 209 // Special permissions 210 if (isset($permissions[CFS_METHODS]) && !empty($permissions[CFS_METHODS])) { 211 foreach ($permissions[CFS_METHODS] as $method => $permissions) { 212 // Make case-insensitive 213 $permissions[CFS_METHODS][strtolower($method)] = $permissions; 214 } 215 if (array_key_exists($action, $permissions[CFS_METHODS])) { 216 // Permission for this method exists 217 $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition(); 218 if ((is_array($permissions[CFS_METHODS][$action]) && !in_array($currentUserPosition, $permissions[CFS_METHODS][$action])) || (!is_array($permissions[CFS_METHODS][$action]) && $permissions[CFS_METHODS][$action] != $currentUserPosition)) { 219 $res = false; 220 } 221 } 222 } 223 if (isset($permissions[CFS_USERLEVELS]) && !empty($permissions[CFS_USERLEVELS])) { 224 $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition(); 225 // For multi-sites network admin role is undefined, let's do this here 226 if (is_multisite() && is_admin() && is_super_admin()) { 227 $currentUserPosition = CFS_ADMIN; 228 } 229 foreach ($permissions[CFS_USERLEVELS] as $userlevel => $methods) { 230 if (is_array($methods)) { 231 $lowerMethods = array_map('strtolower', $methods); // Make case-insensitive 232 if (in_array($action, $lowerMethods)) { 233 // Permission for this method exists 234 if ($currentUserPosition != $userlevel) { 235 $res = false; 236 } 237 break; 238 } 239 } else { 240 $lowerMethod = strtolower($methods); // Make case-insensitive 241 if ($lowerMethod == $action) { 242 // Permission for this method exists 243 if ($currentUserPosition != $userlevel) { 244 $res = false; 245 } 246 break; 247 } 248 } 249 } 250 } 251 } 252 if ($res) { 253 // Additional check for nonces 254 $noncedMethods = $mod->getController()->getNoncedMethods(); 255 if (!empty($noncedMethods)) { 256 $noncedMethods = array_map('strtolower', $noncedMethods); 257 if (in_array($action, $noncedMethods)) { 258 $nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : reqCfs::getVar('_wpnonce'); 259 if (is_admin()) { 260 if (!wp_verify_nonce($nonce, 'cfs_nonce')) { 261 $res = false; 262 } 263 } else { 264 if (!wp_verify_nonce($nonce, 'cfs_nonce_frontend')) { 265 $res = false; 266 } 267 } 268 } 313 $controller = $mod ? $mod->getController() : null; 314 if (!$controller || empty($action) || !is_string($action) || !method_exists($controller, $action)) { 315 return null; 316 } 317 $method = new ReflectionMethod($controller, $action); 318 if (!$method->isPublic() || $method->isStatic()) { 319 return null; 320 } 321 return $controller; 322 } 323 protected function _methodListed($action, $methods) 324 { 325 return !empty($methods) && is_array($methods) && in_array($action, array_map('strtolower', $methods), true); 326 } 327 /** 328 * Get user levels required for action from controller permissions 329 * @param array $permissions Result of controllerCfs::getPermissions() 330 * @param string $action Action name in lower case 331 * @return array List of conditions, each one - array of user levels, any of them pass condition. Empty if action is not declared. 332 */ 333 protected function _getRequiredUserLevels($permissions, $action) 334 { 335 $res = []; 336 if (empty($permissions) || !is_array($permissions)) { 337 return $res; 338 } 339 if (isset($permissions[CFS_METHODS]) && is_array($permissions[CFS_METHODS])) { 340 foreach ($permissions[CFS_METHODS] as $method => $levels) { 341 if (strtolower($method) == $action) { 342 $res[] = (array) $levels; 343 break; 344 } 345 } 346 } 347 if (isset($permissions[CFS_USERLEVELS]) && is_array($permissions[CFS_USERLEVELS])) { 348 foreach ($permissions[CFS_USERLEVELS] as $userlevel => $methods) { 349 if ($this->_methodListed($action, (array) $methods)) { 350 $res[] = [$userlevel]; 351 break; 269 352 } 270 353 } … … 335 418 case 'ajax': 336 419 add_action('wp_ajax_' . $this->_action, [$mod->getController(), $this->_action]); 337 add_action('wp_ajax_nopriv_' . $this->_action, [$mod->getController(), $this->_action]); 420 // Not logged in visitors can reach only actions that controller declared as public 421 if ($this->isPublicAction($this->_mod, $this->_action)) { 422 add_action('wp_ajax_nopriv_' . $this->_action, [$mod->getController(), $this->_action]); 423 } 338 424 break; 339 425 default: -
contact-form-by-supsystic/tags/1.11.1/classes/utils.php
r3679442 r3759933 735 735 } 736 736 return $str; 737 } 738 /** 739 * Make value safe to be placed in email header: line breaks there start new header. 740 * @param mixed $value Header value, or array of values 741 * @return mixed 742 */ 743 public static function cleanMailHeader($value) 744 { 745 if (is_array($value)) { 746 return array_map([__CLASS__, 'cleanMailHeader'], $value); 747 } 748 if (!is_scalar($value)) { 749 return ''; 750 } 751 return trim(preg_replace('/[\r\n\t\0\x0B\x0C]+/', ' ', (string) $value)); 752 } 753 /** 754 * Sendmail path is passed to shell by mailer, so allow only absolute path to sendmail-compatible binary, 755 * with few safe flags. 756 * @param string $path 757 * @return bool 758 */ 759 public static function isValidSendmailPath($path) 760 { 761 if (!is_string($path)) { 762 return false; 763 } 764 $path = trim($path, ' '); 765 if ($path === '') { 766 return true; // Default from php.ini will be used 767 } 768 // Only printable chars, parts are separated by spaces only 769 if (preg_match('/[^\x20-\x7E]/', $path)) { 770 return false; 771 } 772 $parts = preg_split('/ +/', $path); 773 $bin = array_shift($parts); 774 if (!preg_match('#^(?:[A-Za-z]:)?[\\\\/][A-Za-z0-9._\\\\/-]+$#', $bin) || strpos($bin, '..') !== false) { 775 return false; 776 } 777 $binName = basename(str_replace('\\', '/', $bin)); 778 if (!preg_match('/^(sendmail|msmtp|ssmtp|esmtp|exim4?|qmail-inject|mini_sendmail|nullmailer-inject)(\.exe)?$/i', $binName)) { 779 return false; 780 } 781 $emailRe = '/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+$/'; 782 for ($i = 0; $i < count($parts); $i++) { 783 $flag = $parts[$i]; 784 if (in_array($flag, ['-t', '-i', '-oi', '-ti'], true)) { 785 continue; 786 } 787 if (strpos($flag, '-f') === 0 && strlen($flag) > 2 && preg_match($emailRe, substr($flag, 2))) { 788 continue; 789 } 790 if ($flag === '-f' && isset($parts[$i + 1]) && preg_match($emailRe, $parts[$i + 1])) { 791 $i++; 792 continue; 793 } 794 return false; 795 } 796 return true; 737 797 } 738 798 public static function encodeArrayTxt($arr, $forceOrd = false) -
contact-form-by-supsystic/tags/1.11.1/config.php
r3750170 r3759933 53 53 54 54 define('CFS_PLUGIN_INSTALLED', true); 55 define('CFS_VERSION', '1.1 0.7');55 define('CFS_VERSION', '1.11.1'); 56 56 define('CFS_USER', 'user'); 57 57 -
contact-form-by-supsystic/tags/1.11.1/js/core.js
r3491826 r3759933 84 84 var dataType = params.dataType ? params.dataType : 'json'; 85 85 // Set plugin orientation 86 // Admin actions require plugin nonce - add it if request does not have it's own one 87 var adminNonce = cfsGetAdminNonce(); 86 88 if (typeof data == 'string') { 87 89 data += '&pl=' + CFS_DATA.CFS_CODE; 88 90 data += '&reqType=ajax'; 91 if (adminNonce && !/(^|&)_wpnonce=/.test(data)) data += '&_wpnonce=' + encodeURIComponent(adminNonce); 89 92 } else { 90 93 data['pl'] = CFS_DATA.CFS_CODE; 91 94 data['reqType'] = 'ajax'; 95 if (adminNonce && typeof data['_wpnonce'] == 'undefined') data['_wpnonce'] = adminNonce; 92 96 } 93 97 … … 194 198 } 195 199 200 /** 201 * Plugin nonce for admin requests, it is not available on frontend 202 */ 203 function cfsGetAdminNonce() { 204 if (typeof CFS_NONCE != 'undefined' && CFS_NONCE && CFS_NONCE.cfs_nonce) return CFS_NONCE.cfs_nonce; 205 if (typeof CFS_DATA != 'undefined' && CFS_DATA && CFS_DATA.cfsNonce) return CFS_DATA.cfsNonce; 206 return false; 207 } 196 208 function getDialogElementCfs() { 197 209 return jQuery('<div/>').appendTo(jQuery('body')); -
contact-form-by-supsystic/tags/1.11.1/js/core.min.js
r3403065 r3759933 1 1 2 if(typeof(CFS_DATA)=="undefined"){var CFS_DATA={}}if(isNumber(CFS_DATA.animationSpeed)){CFS_DATA.animationSpeed=parseInt(CFS_DATA.animationSpeed)}else{if(jQuery.inArray(CFS_DATA.animationSpeed,["fast","slow"])==-1){CFS_DATA.animationSpeed="fast"}}CFS_DATA.showSubscreenOnCenter=parseInt(CFS_DATA.showSubscreenOnCenter);var sdLoaderImgCfs='<img src="'+CFS_DATA.loader+'" />';var g_cfsAnimationSpeed=300;jQuery.fn.showLoaderCfs=function(){return jQuery(this).html(sdLoaderImgCfs)};jQuery.fn.appendLoaderCfs=function(){jQuery(this).append(sdLoaderImgCfs)};jQuery.sendFormCfs=function(a){return jQuery("<br />").sendFormCfs(a)};jQuery.fn.sendFormCfs=function(e){var b=null;if(!e){e={fid:false,msgElID:false,onSuccess:false}}if(e.fid){b=jQuery("#"+fid)}else{b=jQuery(this)}var c=(jQuery(b).tagName()=="FORM");var f=new Array();if(e.data){f=e.data}else{if(c){f=jQuery(b).serialize()}}if(e.appendData){var h=typeof(f)=="string";var k=[];for(var g in e.appendData){if(h){k.push(g+"="+e.appendData[g])}else{f[g]=e.appendData[g]}}if(h){f+="&"+k.join("&")}}var d=null;if(e.msgElID){if(e.msgElID=="noMessages"){d=false}else{if(typeof(e.msgElID)=="object"){d=e.msgElID}else{d=jQuery("#"+e.msgElID)}}}if(typeof(e.inputsWraper)=="string"){b=jQuery("#"+e.inputsWraper);c=true}if(c&&b){jQuery(b).find("*").removeClass("cfsInputError")}if(d&&!e.btn){jQuery(d).removeClass("cfsSuccessMsg").removeClass("cfsErrorMsg");if(!e.btn){jQuery(d).showLoaderCfs()}}if(e.btn){jQuery(e.btn).attr("disabled","disabled");e.btnIconElement=jQuery(e.btn).find(".fa").length?jQuery(e.btn).find(".fa"):jQuery(e.btn);if(jQuery(e.btn).find(".fa").length){e.btnIconElement.data("prev-class",e.btnIconElement.attr("class")).attr("class","fa fa-spinner fa-spin")}}var a="";if(typeof(e.url)!="undefined"){a=e.url}else{if(typeof(ajaxurl)=="undefined"){a=CFS_DATA.ajaxurl}else{a=ajaxurl}}jQuery(".cfsErrorForField").hide(CFS_DATA.animationSpeed);var j=e.dataType?e.dataType:"json"; if(typeof(f)=="string"){f+="&pl="+CFS_DATA.CFS_CODE;f+="&reqType=ajax"}else{f.pl=CFS_DATA.CFS_CODE;f.reqType="ajax"}jQuery.ajax({url:a,data:f,type:"POST",dataType:j,success:function(i){toeProcessAjaxResponseCfs(i,d,b,c,e);if(e.clearMsg){setTimeout(function(){if(d){jQuery(d).animateClear()}},typeof(e.clearMsg)=="boolean"?5000:e.clearMsg)}}})};jQuery.fn.animateClear=function(){var a=jQuery("<span>"+jQuery(this).html()+"</span>");jQuery(this).html(a);jQuery(a).hide(CFS_DATA.animationSpeed,function(){jQuery(a).remove()})};jQuery.fn.animateRemoveCfs=function(a,b){a=a==undefined?CFS_DATA.animationSpeed:a;jQuery(this).hide(a,function(){jQuery(this).remove();if(typeof(b)==="function"){b()}})};function toeProcessAjaxResponseCfs(h,e,c,d,f){if(typeof(f)=="undefined"){f={}}if(typeof(e)=="string"){e=jQuery("#"+e)}if(e){jQuery(e).html("")}if(f.btn){jQuery(f.btn).removeAttr("disabled");if(f.btnIconElement){f.btnIconElement.attr("class",f.btnIconElement.data("prev-class"))}}if(typeof(h)=="object"){if(h.error){if(e){jQuery(e).removeClass("cfsSuccessMsg").addClass("cfsErrorMsg")}var j=[];for(var a in h.errors){if(d){var b=jQuery(c).find('[name*="'+a+'"]');b.addClass("cfsInputError");if(b.attr("placeholder")){}if(!b.data("keyup-error-remove-binded")){b.keydown(function(){jQuery(this).removeClass("cfsInputError")}).data("keyup-error-remove-binded",1)}}if(jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").exists()){jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").show().html(h.errors[a])}else{if(e){jQuery(e).append(h.errors[a]).append("<br />")}else{j.push(h.errors[a])}}}if(j.length&&f.btn&&jQuery.fn.dialog&&!e){jQuery('<div title="'+toeLangCfs("Really small warning :)")+'" />').html(j.join("<br />")).appendTo("body").dialog({modal:true,width:"500px"})}}else{if(h.messages.length){if(e){jQuery(e).removeClass("cfsErrorMsg").addClass("cfsSuccessMsg");for(var g=0;g<h.messages.length;g++){jQuery(e).append(h.messages[g]).append("<br />")}}}}}if(f.onSuccess&&typeof(f.onSuccess)=="function"){f.onSuccess(h)}}function getDialogElementCfs(){return jQuery("<div/>").appendTo(jQuery("body"))}function toeOptionCfs(a){if(CFS_DATA.options&&CFS_DATA.options[a]){return CFS_DATA.options[a]}return false}function toeLangCfs(a){if(CFS_DATA.siteLang&&CFS_DATA.siteLang[a]){return CFS_DATA.siteLang[a]}return a}function toePagesCfs(a){if(typeof(CFS_DATA)!="undefined"&&CFS_DATA[a]){return CFS_DATA[a]}return false}function toeOptTimeoutHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");setTimeout(function(){if(!jQuery("#cfsOptDescription").attr("toeFixTip")){toeOptHideDescriptionCfs()}},500)}function toeOptShowDescriptionCfs(b,a,d,c){if(typeof(b)!="undefined"&&b!=""){if(!jQuery("#cfsOptDescription").length){jQuery("body").append('<div id="cfsOptDescription"></div>')}if(c){jQuery("#cfsOptDescription").css("right",jQuery(window).width()-(a-10))}else{jQuery("#cfsOptDescription").css("left",a+10)}jQuery("#cfsOptDescription").css("top",d);jQuery("#cfsOptDescription").show(200);jQuery("#cfsOptDescription").html(b)}}function toeOptHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");jQuery("#cfsOptDescription").hide(200)}function toeInArrayCfs(c,b){if(b){for(var a in b){if(b[a]==c){return true}}}return false}function toeShowDialogCustomized(b,a){a=jQuery.extend({resizable:false,width:500,height:300,closeOnEscape:true,open:function(c,d){jQuery(".ui-dialog-titlebar").css({"background-color":"#222222","background-image":"none",border:"none",margin:"0",padding:"0","border-radius":"0",color:"#CFCFCF",height:"27px"});jQuery(".ui-dialog-titlebar-close").css({background:'url("'+CFS_DATA.cssPath+'img/tb-close.png") no-repeat scroll 0 0 transparent',border:"0",width:"15px",height:"15px",padding:"0","border-radius":"0",margin:"7px 7px 0"}).html("");jQuery(".ui-dialog").css({"border-radius":"3px","background-color":"#FFFFFF","background-image":"none",padding:"1px","z-index":"300000",position:"fixed",top:"60px"});jQuery(".ui-dialog-buttonpane").css({"background-color":"#FFFFFF"});jQuery(".ui-dialog-title").css({color:"#CFCFCF",font:"12px sans-serif",padding:"6px 10px 0"});if(a.openCallback&&typeof(a.openCallback)=="function"){a.openCallback(c,d)}jQuery(".ui-widget-overlay").css({"z-index":jQuery(c.target).parents(".ui-dialog:first").css("z-index")-1,"background-image":"none"});if(a.modal&&a.closeOnBg){jQuery(".ui-widget-overlay").unbind("click").bind("click",function(){jQuery(b).dialog("close")})}}},a);return jQuery(b).dialog(a)}function toeSliderMove(a,b){var c=jQuery(a.target).attr("id");jQuery("#toeSliderDisplay_"+c).html(b.value);jQuery("#toeSliderInput_"+c).val(b.value).change()}function cfsCorrectJqueryUsed(){return(typeof(jQuery.fn.sendFormCfs)==="function")}function cfsReloadCoreJs(d,e){var c="",b=["common.js","core.js"];for(var a=0;a<b.length;a++){c+='<script type="text/javascript" class="cfsReloadedScript" src="'+CFS_DATA.jsPath+b[a]+'"><\/script>'}jQuery("head").append(c);if(d){_cfsRunClbAfterCoreReload(d,e)}}function _cfsRunClbAfterCoreReload(a,b){if(cfsCorrectJqueryUsed()){callUserFuncArray(a,b);return}setTimeout(function(){cfsCorrectJqueryUsed(a,b)},500)}function base64_decode(d){var b="";var l,j,g="";var k,h,f,e="";var c=0;var a=/[^A-Za-z0-9\+\/\=]/g;if(a.exec(d)){alert("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding.")}d=d.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{k=keyStr.indexOf(d.charAt(c++));h=keyStr.indexOf(d.charAt(c++));f=keyStr.indexOf(d.charAt(c++));e=keyStr.indexOf(d.charAt(c++));l=(k<<2)|(h>>4);j=((h&15)<<4)|(f>>2);g=((f&3)<<6)|e;b=b+String.fromCharCode(l);if(f!=64){b=b+String.fromCharCode(j)}if(e!=64){b=b+String.fromCharCode(g)}l=j=g="";k=h=f=e=""}while(c<d.length);return unescape(b)};2 if(typeof(CFS_DATA)=="undefined"){var CFS_DATA={}}if(isNumber(CFS_DATA.animationSpeed)){CFS_DATA.animationSpeed=parseInt(CFS_DATA.animationSpeed)}else{if(jQuery.inArray(CFS_DATA.animationSpeed,["fast","slow"])==-1){CFS_DATA.animationSpeed="fast"}}CFS_DATA.showSubscreenOnCenter=parseInt(CFS_DATA.showSubscreenOnCenter);var sdLoaderImgCfs='<img src="'+CFS_DATA.loader+'" />';var g_cfsAnimationSpeed=300;jQuery.fn.showLoaderCfs=function(){return jQuery(this).html(sdLoaderImgCfs)};jQuery.fn.appendLoaderCfs=function(){jQuery(this).append(sdLoaderImgCfs)};jQuery.sendFormCfs=function(a){return jQuery("<br />").sendFormCfs(a)};jQuery.fn.sendFormCfs=function(e){var b=null;if(!e){e={fid:false,msgElID:false,onSuccess:false}}if(e.fid){b=jQuery("#"+fid)}else{b=jQuery(this)}var c=(jQuery(b).tagName()=="FORM");var f=new Array();if(e.data){f=e.data}else{if(c){f=jQuery(b).serialize()}}if(e.appendData){var h=typeof(f)=="string";var k=[];for(var g in e.appendData){if(h){k.push(g+"="+e.appendData[g])}else{f[g]=e.appendData[g]}}if(h){f+="&"+k.join("&")}}var d=null;if(e.msgElID){if(e.msgElID=="noMessages"){d=false}else{if(typeof(e.msgElID)=="object"){d=e.msgElID}else{d=jQuery("#"+e.msgElID)}}}if(typeof(e.inputsWraper)=="string"){b=jQuery("#"+e.inputsWraper);c=true}if(c&&b){jQuery(b).find("*").removeClass("cfsInputError")}if(d&&!e.btn){jQuery(d).removeClass("cfsSuccessMsg").removeClass("cfsErrorMsg");if(!e.btn){jQuery(d).showLoaderCfs()}}if(e.btn){jQuery(e.btn).attr("disabled","disabled");e.btnIconElement=jQuery(e.btn).find(".fa").length?jQuery(e.btn).find(".fa"):jQuery(e.btn);if(jQuery(e.btn).find(".fa").length){e.btnIconElement.data("prev-class",e.btnIconElement.attr("class")).attr("class","fa fa-spinner fa-spin")}}var a="";if(typeof(e.url)!="undefined"){a=e.url}else{if(typeof(ajaxurl)=="undefined"){a=CFS_DATA.ajaxurl}else{a=ajaxurl}}jQuery(".cfsErrorForField").hide(CFS_DATA.animationSpeed);var j=e.dataType?e.dataType:"json";var n=cfsGetAdminNonce();if(typeof(f)=="string"){f+="&pl="+CFS_DATA.CFS_CODE;f+="&reqType=ajax";if(n&&!/(^|&)_wpnonce=/.test(f)){f+="&_wpnonce="+encodeURIComponent(n)}}else{f.pl=CFS_DATA.CFS_CODE;f.reqType="ajax";if(n&&typeof(f._wpnonce)=="undefined"){f._wpnonce=n}}jQuery.ajax({url:a,data:f,type:"POST",dataType:j,success:function(i){toeProcessAjaxResponseCfs(i,d,b,c,e);if(e.clearMsg){setTimeout(function(){if(d){jQuery(d).animateClear()}},typeof(e.clearMsg)=="boolean"?5000:e.clearMsg)}}})};jQuery.fn.animateClear=function(){var a=jQuery("<span>"+jQuery(this).html()+"</span>");jQuery(this).html(a);jQuery(a).hide(CFS_DATA.animationSpeed,function(){jQuery(a).remove()})};jQuery.fn.animateRemoveCfs=function(a,b){a=a==undefined?CFS_DATA.animationSpeed:a;jQuery(this).hide(a,function(){jQuery(this).remove();if(typeof(b)==="function"){b()}})};function toeProcessAjaxResponseCfs(h,e,c,d,f){if(typeof(f)=="undefined"){f={}}if(typeof(e)=="string"){e=jQuery("#"+e)}if(e){jQuery(e).html("")}if(f.btn){jQuery(f.btn).removeAttr("disabled");if(f.btnIconElement){f.btnIconElement.attr("class",f.btnIconElement.data("prev-class"))}}if(typeof(h)=="object"){if(h.error){if(e){jQuery(e).removeClass("cfsSuccessMsg").addClass("cfsErrorMsg")}var j=[];for(var a in h.errors){if(d){var b=jQuery(c).find('[name*="'+a+'"]');b.addClass("cfsInputError");if(b.attr("placeholder")){}if(!b.data("keyup-error-remove-binded")){b.keydown(function(){jQuery(this).removeClass("cfsInputError")}).data("keyup-error-remove-binded",1)}}if(jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").exists()){jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").show().html(h.errors[a])}else{if(e){jQuery(e).append(h.errors[a]).append("<br />")}else{j.push(h.errors[a])}}}if(j.length&&f.btn&&jQuery.fn.dialog&&!e){jQuery('<div title="'+toeLangCfs("Really small warning :)")+'" />').html(j.join("<br />")).appendTo("body").dialog({modal:true,width:"500px"})}}else{if(h.messages.length){if(e){jQuery(e).removeClass("cfsErrorMsg").addClass("cfsSuccessMsg");for(var g=0;g<h.messages.length;g++){jQuery(e).append(h.messages[g]).append("<br />")}}}}}if(f.onSuccess&&typeof(f.onSuccess)=="function"){f.onSuccess(h)}}function cfsGetAdminNonce(){if(typeof(CFS_NONCE)!="undefined"&&CFS_NONCE&&CFS_NONCE.cfs_nonce){return CFS_NONCE.cfs_nonce}if(typeof(CFS_DATA)!="undefined"&&CFS_DATA&&CFS_DATA.cfsNonce){return CFS_DATA.cfsNonce}return false}function getDialogElementCfs(){return jQuery("<div/>").appendTo(jQuery("body"))}function toeOptionCfs(a){if(CFS_DATA.options&&CFS_DATA.options[a]){return CFS_DATA.options[a]}return false}function toeLangCfs(a){if(CFS_DATA.siteLang&&CFS_DATA.siteLang[a]){return CFS_DATA.siteLang[a]}return a}function toePagesCfs(a){if(typeof(CFS_DATA)!="undefined"&&CFS_DATA[a]){return CFS_DATA[a]}return false}function toeOptTimeoutHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");setTimeout(function(){if(!jQuery("#cfsOptDescription").attr("toeFixTip")){toeOptHideDescriptionCfs()}},500)}function toeOptShowDescriptionCfs(b,a,d,c){if(typeof(b)!="undefined"&&b!=""){if(!jQuery("#cfsOptDescription").length){jQuery("body").append('<div id="cfsOptDescription"></div>')}if(c){jQuery("#cfsOptDescription").css("right",jQuery(window).width()-(a-10))}else{jQuery("#cfsOptDescription").css("left",a+10)}jQuery("#cfsOptDescription").css("top",d);jQuery("#cfsOptDescription").show(200);jQuery("#cfsOptDescription").html(b)}}function toeOptHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");jQuery("#cfsOptDescription").hide(200)}function toeInArrayCfs(c,b){if(b){for(var a in b){if(b[a]==c){return true}}}return false}function toeShowDialogCustomized(b,a){a=jQuery.extend({resizable:false,width:500,height:300,closeOnEscape:true,open:function(c,d){jQuery(".ui-dialog-titlebar").css({"background-color":"#222222","background-image":"none",border:"none",margin:"0",padding:"0","border-radius":"0",color:"#CFCFCF",height:"27px"});jQuery(".ui-dialog-titlebar-close").css({background:'url("'+CFS_DATA.cssPath+'img/tb-close.png") no-repeat scroll 0 0 transparent',border:"0",width:"15px",height:"15px",padding:"0","border-radius":"0",margin:"7px 7px 0"}).html("");jQuery(".ui-dialog").css({"border-radius":"3px","background-color":"#FFFFFF","background-image":"none",padding:"1px","z-index":"300000",position:"fixed",top:"60px"});jQuery(".ui-dialog-buttonpane").css({"background-color":"#FFFFFF"});jQuery(".ui-dialog-title").css({color:"#CFCFCF",font:"12px sans-serif",padding:"6px 10px 0"});if(a.openCallback&&typeof(a.openCallback)=="function"){a.openCallback(c,d)}jQuery(".ui-widget-overlay").css({"z-index":jQuery(c.target).parents(".ui-dialog:first").css("z-index")-1,"background-image":"none"});if(a.modal&&a.closeOnBg){jQuery(".ui-widget-overlay").unbind("click").bind("click",function(){jQuery(b).dialog("close")})}}},a);return jQuery(b).dialog(a)}function toeSliderMove(a,b){var c=jQuery(a.target).attr("id");jQuery("#toeSliderDisplay_"+c).html(b.value);jQuery("#toeSliderInput_"+c).val(b.value).change()}function cfsCorrectJqueryUsed(){return(typeof(jQuery.fn.sendFormCfs)==="function")}function cfsReloadCoreJs(d,e){var c="",b=["common.js","core.js"];for(var a=0;a<b.length;a++){c+='<script type="text/javascript" class="cfsReloadedScript" src="'+CFS_DATA.jsPath+b[a]+'"><\/script>'}jQuery("head").append(c);if(d){_cfsRunClbAfterCoreReload(d,e)}}function _cfsRunClbAfterCoreReload(a,b){if(cfsCorrectJqueryUsed()){callUserFuncArray(a,b);return}setTimeout(function(){cfsCorrectJqueryUsed(a,b)},500)}function base64_decode(d){var b="";var l,j,g="";var k,h,f,e="";var c=0;var a=/[^A-Za-z0-9\+\/\=]/g;if(a.exec(d)){alert("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding.")}d=d.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{k=keyStr.indexOf(d.charAt(c++));h=keyStr.indexOf(d.charAt(c++));f=keyStr.indexOf(d.charAt(c++));e=keyStr.indexOf(d.charAt(c++));l=(k<<2)|(h>>4);j=((h&15)<<4)|(f>>2);g=((f&3)<<6)|e;b=b+String.fromCharCode(l);if(f!=64){b=b+String.fromCharCode(j)}if(e!=64){b=b+String.fromCharCode(g)}l=j=g="";k=h=f=e=""}while(c<d.length);return unescape(b)}; -
contact-form-by-supsystic/tags/1.11.1/modules/forms/controller.php
r3679442 r3759933 622 622 return ['save', 'removeGroup', 'getListForTbl', 'saveAsCopy', 'remove', 'createFromTpl', 'changeTpl']; 623 623 } 624 /** 625 * contact() checks it's own per-form nonce, updateNonce() just gives fresh nonce for cached pages 626 */ 627 public function getPublicMethods() 628 { 629 return ['contact', 'updateNonce']; 630 } 624 631 public function getPermissions() 625 632 { -
contact-form-by-supsystic/tags/1.11.1/modules/forms/models/forms.php
r3640942 r3759933 204 204 } 205 205 if (empty($errorMsg)) { 206 // Not mandatory email can be empty, but if it is entered - it must be valid 207 if ($htmlType == 'email' && $value && (!is_string($value) || !is_email($value))) { 208 $errorMsg = empty($formInvalidError) ? __('Invalid value for %s', CFS_LANG_CODE) : $formInvalidError; 209 } 210 } 211 if (empty($errorMsg)) { 206 212 // Start other validation process 207 213 if (!$isDate && isset($f['min_size']) && !empty($f['min_size']) && ($minSize = (int) $f['min_size'])) { … … 315 321 // This is requiredfor case when you hav select box with vals = mail1@mail.com, ... and names User Name 1, ... 316 322 // To send to it's values, not to it's names 317 $variablesWithSelectVals['user_' . $sendName] = $ fieldsData[$sendName];323 $variablesWithSelectVals['user_' . $sendName] = $this->_getSelectedOptionValue($f, isset($fieldsData[$sendName]) ? $fieldsData[$sendName] : ''); 318 324 break; 319 325 default: … … 324 330 } 325 331 } 332 // Submitted values can be mapped to mail headers - line breaks there would start new headers 333 $headerVariables = utilsCfs::cleanMailHeader($variables); 334 $headerVariablesWithSelectVals = utilsCfs::cleanMailHeader($variablesWithSelectVals); 326 335 $sendForceTo = dispatcherCfs::applyFilters('sendContactTo', '', $fieldsData, $form); 327 336 foreach ($form['params']['submit'] as $s) { … … 334 343 $additionalHeaders = []; 335 344 if (isset($s['enb_cc']) && (int) $s['enb_cc'] && isset($s['cc']) && !empty($s['cc'])) { 336 $additionalHeaders[] = 'Cc: ' . utilsCfs:: replaceVariables($s['cc'], $variables);345 $additionalHeaders[] = 'Cc: ' . utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['cc'], $headerVariables)); 337 346 } 338 347 if (isset($s['from']) && !empty($s['from'])) { 339 $additionalHeaders[] = 'From: ' . utilsCfs:: replaceVariables($s['from'], $variables);348 $additionalHeaders[] = 'From: ' . utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['from'], $headerVariables)); 340 349 } 341 350 if (isset($s['reply']) && !empty($s['reply'])) { 342 $additionalHeaders[] = 'Reply-To: ' . utilsCfs::replaceVariables($s['reply'], $variables); 343 } 344 $to = utilsCfs::replaceVariables($to, $variablesWithSelectVals); 345 $subject = utilsCfs::replaceVariables($s['subject'], $variables); 351 $additionalHeaders[] = 'Reply-To: ' . utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['reply'], $headerVariables)); 352 } 353 $to = utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($to, $headerVariablesWithSelectVals)); 354 if (empty($to)) { 355 continue; // Recipient was taken from submitted data, and it was not valid 356 } 357 $subject = utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['subject'], $headerVariables)); 346 358 // Let it be only for Message field 347 359 //$msg = nl2br(utilsCfs::replaceVariables($msg, array_merge($variables, array('form_data' => $sendFormDataStr)))); … … 363 375 } 364 376 return true; 377 } 378 /** 379 * Submitted select box value can be used as recipient email, @see sendContact(), 380 * so it is accepted only if it is one of field options 381 * @param array $field Select box field 382 * @param mixed $value Submitted value 383 * @return string Value, or empty string if there is no such option 384 */ 385 private function _getSelectedOptionValue($field, $value) 386 { 387 if (!is_string($value) || $value === '' || empty($field['options']) || !is_array($field['options'])) { 388 return ''; 389 } 390 // Options are prepared in same way as submitted data, @see contact() 391 foreach (dbCfs::prepareHtmlIn($field['options']) as $opt) { 392 if (isset($opt['name']) && (string) $opt['name'] === $value) { 393 return $value; 394 } 395 } 396 return ''; 365 397 } 366 398 private function _generateSendFormData($fieldsData, $form) … … 782 814 for ($i = 0; $i < (int) $d['params']['opts_attrs']['txt_block_number']; $i++) { 783 815 $sendValKey = 'params_tpl_txt_val_' . $i; 784 if (isset($d[$sendValKey])) { 785 $d['params']['tpl']['txt_' . $i] = urldecode($d[$sendValKey]); 816 if (isset($d[$sendValKey]) && is_string($d[$sendValKey])) { 817 // Text is sent url-encoded, so request filter did not see real value - filter it after decode 818 $d['params']['tpl']['txt_' . $i] = reqCfs::sanitizeString(urldecode($d[$sendValKey])); 786 819 } 787 820 } -
contact-form-by-supsystic/tags/1.11.1/modules/forms/views/forms.php
r3750170 r3759933 5 5 { 6 6 protected $_twig; 7 /** 8 * Tags values for current render: placeholder => value, @see _addTwigValue() 9 */ 10 private $_twigValues = []; 11 private $_twigValuesKey = ''; 7 12 private $_renderFormIter = 0; 8 13 private $_lastForm = null; … … 14 19 frameCfs::_()->addScript('admin.forms', $this->getModule()->getModPath() . 'js/admin.forms.js'); 15 20 frameCfs::_()->addScript('admin.forms.list', $this->getModule()->getModPath() . 'js/admin.forms.list.js'); 16 frameCfs::_()->addJSVar('admin.forms.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getListForTbl', ['reqType' => 'ajax' ]));21 frameCfs::_()->addJSVar('admin.forms.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getListForTbl', ['reqType' => 'ajax', '_wpnonce' => wp_create_nonce('cfs_nonce')])); 17 22 18 23 $this->assign('addNewLink', frameCfs::_()->getModule('options')->getTabUrl('forms_add_new')); … … 114 119 ]; 115 120 116 $this->assign('csvExportUrl', uriCfs::mod('forms', 'exportCsv', ['id' => $id ]));121 $this->assign('csvExportUrl', uriCfs::mod('forms', 'exportCsv', ['id' => $id, '_wpnonce' => wp_create_nonce('cfs_nonce')])); 117 122 118 123 $this->assign('adminEmail', get_bloginfo('admin_email')); … … 123 128 $this->assign('cfsAddNewUrl', $cfsAddNewUrl); 124 129 $this->assign('bgTypes', $bgType); 125 $this->assign('previewUrl', uriCfs::mod('forms', 'getPreviewHtml', ['id' => $id ]));130 $this->assign('previewUrl', uriCfs::mod('forms', 'getPreviewHtml', ['id' => $id, '_wpnonce' => wp_create_nonce('cfs_nonce')])); 126 131 $this->assign('form', $form); 127 132 $this->assign('fieldTypes', $fieldTypes); … … 473 478 public function adjustOpacity($color, $alpha) 474 479 { 480 $color = $this->_resolveTwigValues($color); 481 $alpha = $this->_resolveTwigValues($alpha); 475 482 $alpha = max(0, min(1, $alpha)); 476 483 $rgbColor = utilsCfs::hexToRgb($color); … … 478 485 return 'rgba(' . implode(',', $rgbColor) . ')'; 479 486 } 487 public function hexToRgbaStr($hex, $alpha = 1) 488 { 489 return utilsCfs::hexToRgbaStr($this->_resolveTwigValues($hex), $this->_resolveTwigValues($alpha)); 490 } 480 491 public function adjustBrightness($hex, $steps) 481 492 { 493 $hex = $this->_resolveTwigValues($hex); 494 $steps = $this->_resolveTwigValues($steps); 482 495 // Steps should be between -255 and 255. Negative = darker, positive = lighter 483 496 $steps = max(-255, min(255, $steps)); … … 525 538 526 539 $form['css'] = $this->_replaceTagsWithTwig($form['css'], $form); 540 $htmlValuesFrom = count($this->_twigValues); 527 541 $form['html'] = $this->_replaceTagsWithTwig($form['html'], $form); 528 542 529 $form['html'] = str_replace('col-md-', 'supMd', $form['html']); 530 $form['html'] = str_replace('col-xs-', 'supXs', $form['html']); 531 $form['html'] = str_replace('col-sm-', 'supSm', $form['html']); 532 $form['html'] = str_replace('col-lg-', 'supLg', $form['html']); 533 $form['html'] = str_replace('row', 'supRow', $form['html']); 543 $colReplaceFrom = ['col-md-', 'col-xs-', 'col-sm-', 'col-lg-', 'row']; 544 $colReplaceTo = ['supMd', 'supXs', 'supSm', 'supLg', 'supRow']; 545 $form['html'] = str_replace($colReplaceFrom, $colReplaceTo, $form['html']); 546 // Values of tags in html were always processed by this replacement too 547 foreach (array_slice(array_keys($this->_twigValues), $htmlValuesFrom) as $valueKey) { 548 $this->_twigValues[$valueKey] = str_replace($colReplaceFrom, $colReplaceTo, $this->_twigValues[$valueKey]); 549 } 534 550 535 551 $form['html'] .= $this->_generateImgsPreload($form); … … 540 556 // it will not recognize css in js data as style whye rendering on server side, 541 557 // but will be replaced back to normal <style> tag in JS, @see js/frontend.forms.js 542 return $this->_twig->render(558 $tpl = 543 559 ($replaceStyleTag ? '<span style="display: none;" id="cfsFormStylesHidden_' . $form['view_id'] . '">' : '<style type="text/css" id="' . $form['view_html_id'] . '_style">') . 544 $form['css'] . 545 ($replaceStyleTag ? '</span>' : '</style>') . 546 '<div id="' . 547 $form['view_html_id'] . 548 '" class="cfsFormShell">' . 549 $form['html'] . 550 '</div>', 551 ['forms' => $form], 552 ); 560 $form['css'] . 561 ($replaceStyleTag ? '</span>' : '</style>') . 562 '<div id="' . 563 $form['view_html_id'] . 564 '" class="cfsFormShell">' . 565 $form['html'] . 566 '</div>'; 567 $obLevel = ob_get_level(); 568 try { 569 $res = $this->_twig->render($tpl, ['forms' => $form]); 570 } catch (Throwable $e) { 571 // Twig cleans own output buffer only for exceptions, not for PHP errors 572 while (ob_get_level() > $obLevel) { 573 ob_end_clean(); 574 } 575 // String loader uses whole template as it's name - so full Twig message would contain all template 576 $errorMsg = $e instanceof Twig_Error ? $e->getRawMessage() : $e->getMessage(); 577 error_log('Contact Form by Supsystic: can not render form #' . $form['id'] . ': ' . $errorMsg); 578 return frameCfs::_()->getModule('user')->isAdmin() ? esc_html(sprintf(__('Can not render form template: %s', CFS_LANG_CODE), $errorMsg)) : ''; 579 } 580 // Put tags values only now - so they are never parsed by template engine 581 return $this->_insertTwigValues($res); 553 582 } 554 583 private function _generateCommonFormCss($form) 555 584 { 556 585 $res = ''; 557 $res .= '#[SHELL_ID] { width: ' . $form['params']['tpl']['width'] . $form['params']['tpl']['width_measure'] . '}'; 586 // Values go through tags too, @see _replaceTagsWithTwig() 587 $res .= '#[SHELL_ID] { width: ' . (isset($form['params']['tpl']['width']) ? '[width]' : '') . (isset($form['params']['tpl']['width_measure']) ? '[width_measure]' : '') . '}'; 558 588 if (isset($form['params'], $form['params']['tpl'], $form['params']['tpl']['form_sent_msg_color']) && !empty($form['params']['tpl']['form_sent_msg_color'])) { 559 $res .= '#[SHELL_ID] .cfsSuccessMsg { color: ' . $form['params']['tpl']['form_sent_msg_color'] . '!important}';589 $res .= '#[SHELL_ID] .cfsSuccessMsg { color: [form_sent_msg_color] !important}'; 560 590 } 561 591 return $res; … … 863 893 foreach ($replaceFrom as $i => $v) { 864 894 $replaceFrom[$i] = '[' . $v . ']'; 895 // Tags values are users data: put them in template only as placeholders, real values are inserted 896 // after template render, so they are never evaluated by template engine. First 4 tags - are template syntax. 897 if ($i > 3) { 898 $replaceTo[$i] = $this->_addTwigValue($replaceTo[$i]); 899 } 865 900 } 866 901 return str_replace($replaceFrom, $replaceTo, $string); 902 } 903 /** 904 * Register value for template and get it's placeholder 905 * @param mixed $value 906 * @return string Placeholder: it is safe for any template place - text, or string in Twig expression 907 */ 908 private function _addTwigValue($value) 909 { 910 if (empty($this->_twigValuesKey)) { 911 // Unpredictable, and contains only chars that will not be changed by any template replacements 912 $this->_twigValuesKey = strtoupper(substr(md5(uniqid('', true) . wp_rand()), 0, 12)); 913 } 914 $placeholder = '__CFSV' . $this->_twigValuesKey . '_' . count($this->_twigValues) . '__'; 915 // Same line breaks normalization as Twig lexer did, when values were part of template 916 $this->_twigValues[$placeholder] = is_scalar($value) ? str_replace(["\r\n", "\r"], "\n", (string) $value) : ''; 917 return $placeholder; 918 } 919 private function _insertTwigValues($str) 920 { 921 // strtr() makes all replacements in one pass, so inserted values are not processed again 922 return empty($this->_twigValues) ? $str : strtr($str, $this->_twigValues); 923 } 924 /** 925 * Template functions get placeholders as arguments, @see adjustBrightness() 926 */ 927 private function _resolveTwigValues($value) 928 { 929 return is_string($value) && strpos($value, '__CFSV') !== false ? $this->_insertTwigValues($value) : $value; 867 930 } 868 931 protected function _initTwig() … … 873 936 } 874 937 Twig_Autoloader::register(); 938 importClassCfs('twigSecurityPolicyCfs', CFS_CLASSES_DIR . 'twigSecurityPolicy.php'); 875 939 $this->_twig = new Twig_Environment(new Twig_Loader_String(), ['debug' => 0]); 940 // Templates can be edited in admin area - so they are always rendered in sandbox 941 $this->_twig->addExtension(new Twig_Extension_Sandbox(new twigSecurityPolicyCfs(), true)); 876 942 $this->_twig->addFunction(new Twig_SimpleFunction('adjust_brightness', [$this, 'adjustBrightness'])); 877 943 $this->_twig->addFunction(new Twig_SimpleFunction('adjust_opacity', [$this, 'adjustOpacity'])); 878 $this->_twig->addFunction(new Twig_SimpleFunction('hex_to_rgba_str', 'utilsCfs::hexToRgbaStr'));944 $this->_twig->addFunction(new Twig_SimpleFunction('hex_to_rgba_str', [$this, 'hexToRgbaStr'])); 879 945 } 880 946 } … … 885 951 frameCfs::_()->addScript('admin.forms', $this->getModule()->getModPath() . 'js/admin.forms.js'); 886 952 frameCfs::_()->addScript('admin.forms.contacts.list', $this->getModule()->getModPath() . 'js/admin.forms.contacts.list.js'); 887 frameCfs::_()->addJSVar('admin.forms.contacts.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getContactsListForTbl', ['reqType' => 'ajax', 'fid' => $fid ]));953 frameCfs::_()->addJSVar('admin.forms.contacts.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getContactsListForTbl', ['reqType' => 'ajax', 'fid' => $fid, '_wpnonce' => wp_create_nonce('cfs_nonce')])); 888 954 $allForms = $this->getModel('forms')->getAllFromTbl(); 889 955 $allFormsForSelect = []; -
contact-form-by-supsystic/tags/1.11.1/modules/forms/views/tpl/formsEditFormStatistics.php
r3491826 r3759933 39 39 <a href="#" class="button cfsStatChartGroupBtn" data-stat-group="month" data-chart="cfsMainStats"><?php _e('Month', CFS_LANG_CODE); ?></a> 40 40 | 41 <a href="<?php echo uriCfs::mod('statistics', 'getCsv' ); ?>" target="_blank" class="button cfsStatExportCsv" data-chart="cfsMainStats"><?php _e('Export to CSV', CFS_LANG_CODE); ?></a>41 <a href="<?php echo uriCfs::mod('statistics', 'getCsv', ['_wpnonce' => wp_create_nonce('cfs_nonce')]); ?>" target="_blank" class="button cfsStatExportCsv" data-chart="cfsMainStats"><?php _e('Export to CSV', CFS_LANG_CODE); ?></a> 42 42 | 43 43 </span> -
contact-form-by-supsystic/tags/1.11.1/modules/mail/mod.php
r3491826 r3759933 7 7 public function send($to, $subject, $message, $fromName = '', $fromEmail = '', $replyToName = '', $replyToEmail = '', $additionalHeaders = [], $additionalParameters = []) 8 8 { 9 // Line breaks in any of header values would inject new mail headers 10 list($to, $subject, $fromName, $fromEmail, $replyToName, $replyToEmail) = utilsCfs::cleanMailHeader([$to, $subject, $fromName, $fromEmail, $replyToName, $replyToEmail]); 11 $additionalHeaders = empty($additionalHeaders) ? [] : array_filter(utilsCfs::cleanMailHeader((array) $additionalHeaders)); 9 12 $type = frameCfs::_()->getModule('options')->get('mail_send_engine'); 10 13 $res = false; … … 69 72 $this->_sendMailMailer = new PHPMailer\PHPMailer\PHPMailer(true); // create a new object 70 73 $this->_sendMailMailer->isSendmail(); // enable SendMail 71 $sendMailPath = trim(frameCfs::_()->getModule('options')->get('sendmail_path')); 72 if (!empty($sendMailPath)) { 74 $sendMailPath = trim((string) frameCfs::_()->getModule('options')->get('sendmail_path')); 75 // Value could be saved before validation was added - never pass invalid one to shell 76 if (!empty($sendMailPath) && utilsCfs::isValidSendmailPath($sendMailPath)) { 73 77 $this->_sendMailMailer->Sendmail = $sendMailPath; 74 78 } -
contact-form-by-supsystic/tags/1.11.1/modules/mail/views/tpl/mailAdmin.php
r3491826 r3759933 6 6 <?php echo htmlCfs::hidden('mod', ['value' => 'mail']); ?> 7 7 <?php echo htmlCfs::hidden('action', ['value' => 'testEmail']); ?> 8 <?php echo htmlCfs::defaultNonceForAdminPanel(); ?> 8 9 <button class="button button-primary"> 9 10 <i class="fa fa-paper-plane"></i> … … 63 64 <?php echo htmlCfs::hidden('mod', ['value' => 'mail']); ?> 64 65 <?php echo htmlCfs::hidden('action', ['value' => 'saveOptions']); ?> 66 <?php echo htmlCfs::defaultNonceForAdminPanel(); ?> 65 67 <button class="button button-primary"> 66 68 <i class="fa fa-fw fa-save"></i> -
contact-form-by-supsystic/tags/1.11.1/modules/options/models/options.php
r3641551 r3759933 22 22 { 23 23 if (isset(self::$_restrictedOptionValues[$optKey]) && !in_array($val, self::$_restrictedOptionValues[$optKey], true)) { 24 return; 25 } 26 if (!$this->_isValidOptValue($optKey, $val)) { 24 27 return; 25 28 } … … 70 73 { 71 74 if (isset($d['opt_values']) && is_array($d['opt_values']) && !empty($d['opt_values'])) { 75 if (isset($d['opt_values']['sendmail_path']) && !$this->_isValidOptValue('sendmail_path', $d['opt_values']['sendmail_path'])) { 76 // Field is always submitted with mail options, but matters only for Sendmail engine 77 if (isset($d['opt_values']['mail_send_engine']) && $d['opt_values']['mail_send_engine'] === 'sendmail') { 78 $this->pushError(__('Invalid Sendmail Path: it should be absolute path to sendmail binary, for example /usr/sbin/sendmail', CFS_LANG_CODE), 'opt_values[sendmail_path]'); 79 return false; 80 } 81 unset($d['opt_values']['sendmail_path']); 82 } 72 83 dispatcherCfs::doAction('beforeSaveOpts', $d); 73 84 foreach ($d['opt_values'] as $code => $val) { … … 80 91 } 81 92 return false; 93 } 94 private function _isValidOptValue($optKey, $val) 95 { 96 switch ($optKey) { 97 case 'sendmail_path': 98 return utilsCfs::isValidSendmailPath($val); 99 } 100 return true; 82 101 } 83 102 private function _updateOptsInDb() -
contact-form-by-supsystic/tags/1.11.1/modules/statistics/controller.php
r3491826 r3759933 80 80 $res->ajaxExec(); 81 81 } 82 /** 83 * add() is called from frontend and checks connect_hash on it's own. 84 * Inherited removeGroup() and clear() are not listed anywhere - so they can not be called by request. 85 */ 86 public function getPublicMethods() 87 { 88 return ['add']; 89 } 82 90 public function getPermissions() 83 91 { -
contact-form-by-supsystic/tags/1.11.1/modules/templates/mod.php
r3640942 r3759933 96 96 } 97 97 $jsData['cfsAcShow'] = $show; 98 // All admin requests require plugin nonce, @see frameCfs::havePermissions() 99 if (frameCfs::_()->getModule('user')->isAdmin()) { 100 $jsData['cfsNonce'] = wp_create_nonce('cfs_nonce'); 101 } 98 102 } 99 103 $jsData = dispatcherCfs::applyFilters('jsInitVariables', $jsData); -
contact-form-by-supsystic/tags/1.11.1/readme.txt
r3750170 r3759933 4 4 Tested up to: 7.1 5 5 Requires PHP: 7.3 6 Stable tag: 1.1 0.76 Stable tag: 1.11.1 7 7 License: GPLv2 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 169 169 = 2026 = 170 170 171 = 1.11.1 — October 22, 2026 = 172 173 * Maintenance release with the latest Contact Form updates. 174 175 = 1.11.0 — October 22, 2026 = 176 177 * General security hardening and code improvements. 178 171 179 = 1.10.7 — October 16, 2026 = 172 180 -
contact-form-by-supsystic/trunk/cfs.php
r3750257 r3759933 5 5 * Plugin URI: https://supsystic.com/plugins/contact-form-plugin/ 6 6 * Description: Drag-and-drop contact form builder with ready templates, 25+ field types, reCAPTCHA, saved submissions and form statistics. No coding needed. 7 * Version: 1.1 0.77 * Version: 1.11.1 8 8 * Author: supsystic.com 9 9 * Author URI: https://supsystic.com -
contact-form-by-supsystic/trunk/classes/controller.php
r3679442 r3759933 104 104 public function __call($name, $arguments) 105 105 { 106 // delete()/clear() wipe the entire table when called with no/null arguments, 107 // which is exactly how they get invoked here (AJAX dispatch never actually 108 // passes $arguments through). Neither is reliably listed in every controller's 109 // getPermissions(), and havePermissions() defaults to "allow" for any action 110 // name it doesn't recognize - so without this check, any visitor could delete 111 // all data in a table simply by requesting action=delete or action=clear. 106 // delete()/clear() wipe the entire table when called with no/null arguments. 107 // Request dispatcher never routes actions here (frameCfs::havePermissions() accepts 108 // only real declared controller methods), but keep this guard for any other caller. 112 109 if (in_array(strtolower($name), ['delete', 'clear'], true)) { 113 110 return false; … … 136 133 ); 137 134 * Can be used on of sub-array - CFS_METHODS or CFS_USERLEVELS 135 * Methods that are not listed here and not listed in getPublicMethods() can not be called by request at all. 138 136 */ 139 137 public function getPermissions() … … 142 140 } 143 141 /** 144 * Methods that require nonce to be generated 142 * Methods that can be called by request from any visitor, including not logged in users. 143 * Each of them must validate request on it's own (own nonce, hash, etc.). 145 144 * If need - should be redefined in each controller where it required. 146 145 * @return array 147 146 */ 147 public function getPublicMethods() 148 { 149 return []; 150 } 151 /** 152 * Methods from getPermissions() that are opened by direct links from outside of plugin pages 153 * (for example - OAuth callbacks), so they can not carry plugin nonce. 154 * All other methods from getPermissions() always require valid plugin nonce. 155 * @return array 156 */ 157 public function getNonceExemptMethods() 158 { 159 return []; 160 } 161 /** 162 * Public methods that require plugin nonce too. 163 * Methods from getPermissions() require it anyway, @see frameCfs::havePermissions(). 164 * @return array 165 */ 148 166 public function getNoncedMethods() 149 167 { 150 168 return []; 169 } 170 /** 171 * Check that current request was sent by plugin administrator from plugin pages 172 * @return bool 173 */ 174 protected function _isAdminRequest() 175 { 176 return frameCfs::_()->getModule('user')->isAdmin() && frameCfs::_()->verifyNonce(); 151 177 } 152 178 public function getModule() … … 234 260 { 235 261 $res = new responseCfs(); 236 if ($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) { 262 // Inherited by all controllers - so check access here too, not only in request dispatcher 263 if (!$this->_isAdminRequest()) { 264 $res->pushError(__('You have no permissions to do this', CFS_LANG_CODE)); 265 } elseif ($this->getModel()->removeGroup(reqCfs::getVar('listIds', 'post'))) { 237 266 $res->addMessage(__('Done', CFS_LANG_CODE)); 238 267 } else { … … 244 273 { 245 274 $res = new responseCfs(); 246 if ($this->getModel()->clear()) { 275 if (!$this->_isAdminRequest()) { 276 $res->pushError(__('You have no permissions to do this', CFS_LANG_CODE)); 277 } elseif ($this->getModel()->clear()) { 247 278 $res->addMessage(__('Done', CFS_LANG_CODE)); 248 279 } else { -
contact-form-by-supsystic/trunk/classes/frame.php
r3641551 r3759933 23 23 private $_mod = ''; 24 24 private $_action = ''; 25 /** 26 * PRO before 1.5.0 does not declare it's public and nonce exempt methods, @see _isLegacyPro() 27 */ 28 private static $_legacyProPublicMethods = [ 29 'add_fields' => ['uploadFile', 'getFile', 'removeFile'], 30 'wp_subscribe' => ['confirm'], 31 ]; 32 private static $_legacyProNonceExemptMethods = [ 33 'campaignmonitor' => ['saveAccessToken'], 34 'constantcontact' => ['saveAccessToken'], 35 'verticalresponse' => ['saveAccessToken'], 36 // Read only exports - old PRO opens them by links without nonce 37 'ab_testing' => ['getListForTbl'], 38 'wp_subscribe' => ['getWpCsvList'], 39 'statistics' => ['getCsv'], 40 ]; 41 private static $_legacyPro = null; 25 42 /** 26 43 * Object with result of executing non-ajax module request … … 194 211 } 195 212 /** 196 * Check permissions for action in controller by $code 213 * Check permissions for action in controller by $code. 214 * Access is denied by default: an action can be dispatched only if its controller declares it, 215 * either as public (getPublicMethods() - such method must validate the request on its own), 216 * or for some user level (getPermissions()). Every action that is not public requires 217 * a valid plugin nonce too, except actions from getNonceExemptMethods(). 197 218 * @param string $code Code of controller that need to be checked 198 219 * @param string $action Action that need to be checked … … 201 222 public function havePermissions($code, $action) 202 223 { 203 $res = true; 224 $controller = $this->_getDispatchController($code, $action); 225 if (!$controller) { 226 return false; 227 } 228 $action = strtolower($action); 229 if ($this->_methodListed($action, $this->_getPublicMethods($code, $controller))) { 230 // Public methods can be additionally enrolled for the plugin nonce 231 return !$this->_methodListed($action, $controller->getNoncedMethods()) || $this->verifyNonce(); 232 } 233 $requiredLevels = $this->_getRequiredUserLevels($controller->getPermissions(), $action); 234 if (empty($requiredLevels)) { 235 // Action was not declared by controller - deny it 236 return false; 237 } 238 $currentUserPosition = $this->getModule('user')->getCurrentUserPosition(); 239 // For multi-sites network admin role is undefined, let's do this here 240 if (is_multisite() && is_admin() && is_super_admin()) { 241 $currentUserPosition = CFS_ADMIN; 242 } 243 foreach ($requiredLevels as $levels) { 244 if (!in_array($currentUserPosition, $levels, true)) { 245 return false; 246 } 247 } 248 if (!$this->_methodListed($action, $this->_getNonceExemptMethods($code, $controller)) && !$this->verifyNonce()) { 249 return false; 250 } 251 return true; 252 } 253 /** 254 * PRO add-on can be older than this plugin: before 1.5.0 it did not declare access for it's methods 255 * @return bool 256 */ 257 protected function _isLegacyPro() 258 { 259 if (self::$_legacyPro === null) { 260 self::$_legacyPro = function_exists('getProPlugCodeCfs') && !defined('CFS_PRO_DECLARES_ACCESS'); 261 } 262 return self::$_legacyPro; 263 } 264 protected function _getPublicMethods($code, $controller) 265 { 266 $methods = (array) $controller->getPublicMethods(); 267 if ($this->_isLegacyPro() && isset(self::$_legacyProPublicMethods[$code])) { 268 $methods = array_merge($methods, self::$_legacyProPublicMethods[$code]); 269 } 270 return $methods; 271 } 272 protected function _getNonceExemptMethods($code, $controller) 273 { 274 $methods = (array) $controller->getNonceExemptMethods(); 275 if ($this->_isLegacyPro() && isset(self::$_legacyProNonceExemptMethods[$code])) { 276 $methods = array_merge($methods, self::$_legacyProNonceExemptMethods[$code]); 277 } 278 return $methods; 279 } 280 /** 281 * Check if action is allowed for any visitor, including not logged in users 282 * @param string $code Code of controller that need to be checked 283 * @param string $action Action that need to be checked 284 * @return bool 285 */ 286 public function isPublicAction($code, $action) 287 { 288 $controller = $this->_getDispatchController($code, $action); 289 return $controller && $this->_methodListed(strtolower($action), $this->_getPublicMethods($code, $controller)); 290 } 291 /** 292 * Verify plugin nonce from current request 293 * @return bool 294 */ 295 public function verifyNonce() 296 { 297 $nonce = isset($_REQUEST['_wpnonce']) && is_string($_REQUEST['_wpnonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])) : ''; 298 if (empty($nonce)) { 299 return false; 300 } 301 return wp_verify_nonce($nonce, 'cfs_nonce') || wp_verify_nonce($nonce, 'cfs_nonce_frontend'); 302 } 303 /** 304 * Get controller of module, if action can be dispatched to it: it should be real public controller method, 305 * not some name that will be routed through controllerCfs::__call() to it's model. 306 * @param string $code Module code 307 * @param string $action Action name 308 * @return controllerCfs|null 309 */ 310 protected function _getDispatchController($code, $action) 311 { 204 312 $mod = $this->getModule($code); 205 $action = strtolower($action); 206 if ($mod) { 207 $permissions = $mod->getController()->getPermissions(); 208 if (!empty($permissions)) { 209 // Special permissions 210 if (isset($permissions[CFS_METHODS]) && !empty($permissions[CFS_METHODS])) { 211 foreach ($permissions[CFS_METHODS] as $method => $permissions) { 212 // Make case-insensitive 213 $permissions[CFS_METHODS][strtolower($method)] = $permissions; 214 } 215 if (array_key_exists($action, $permissions[CFS_METHODS])) { 216 // Permission for this method exists 217 $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition(); 218 if ((is_array($permissions[CFS_METHODS][$action]) && !in_array($currentUserPosition, $permissions[CFS_METHODS][$action])) || (!is_array($permissions[CFS_METHODS][$action]) && $permissions[CFS_METHODS][$action] != $currentUserPosition)) { 219 $res = false; 220 } 221 } 222 } 223 if (isset($permissions[CFS_USERLEVELS]) && !empty($permissions[CFS_USERLEVELS])) { 224 $currentUserPosition = frameCfs::_()->getModule('user')->getCurrentUserPosition(); 225 // For multi-sites network admin role is undefined, let's do this here 226 if (is_multisite() && is_admin() && is_super_admin()) { 227 $currentUserPosition = CFS_ADMIN; 228 } 229 foreach ($permissions[CFS_USERLEVELS] as $userlevel => $methods) { 230 if (is_array($methods)) { 231 $lowerMethods = array_map('strtolower', $methods); // Make case-insensitive 232 if (in_array($action, $lowerMethods)) { 233 // Permission for this method exists 234 if ($currentUserPosition != $userlevel) { 235 $res = false; 236 } 237 break; 238 } 239 } else { 240 $lowerMethod = strtolower($methods); // Make case-insensitive 241 if ($lowerMethod == $action) { 242 // Permission for this method exists 243 if ($currentUserPosition != $userlevel) { 244 $res = false; 245 } 246 break; 247 } 248 } 249 } 250 } 251 } 252 if ($res) { 253 // Additional check for nonces 254 $noncedMethods = $mod->getController()->getNoncedMethods(); 255 if (!empty($noncedMethods)) { 256 $noncedMethods = array_map('strtolower', $noncedMethods); 257 if (in_array($action, $noncedMethods)) { 258 $nonce = isset($_REQUEST['_wpnonce']) ? $_REQUEST['_wpnonce'] : reqCfs::getVar('_wpnonce'); 259 if (is_admin()) { 260 if (!wp_verify_nonce($nonce, 'cfs_nonce')) { 261 $res = false; 262 } 263 } else { 264 if (!wp_verify_nonce($nonce, 'cfs_nonce_frontend')) { 265 $res = false; 266 } 267 } 268 } 313 $controller = $mod ? $mod->getController() : null; 314 if (!$controller || empty($action) || !is_string($action) || !method_exists($controller, $action)) { 315 return null; 316 } 317 $method = new ReflectionMethod($controller, $action); 318 if (!$method->isPublic() || $method->isStatic()) { 319 return null; 320 } 321 return $controller; 322 } 323 protected function _methodListed($action, $methods) 324 { 325 return !empty($methods) && is_array($methods) && in_array($action, array_map('strtolower', $methods), true); 326 } 327 /** 328 * Get user levels required for action from controller permissions 329 * @param array $permissions Result of controllerCfs::getPermissions() 330 * @param string $action Action name in lower case 331 * @return array List of conditions, each one - array of user levels, any of them pass condition. Empty if action is not declared. 332 */ 333 protected function _getRequiredUserLevels($permissions, $action) 334 { 335 $res = []; 336 if (empty($permissions) || !is_array($permissions)) { 337 return $res; 338 } 339 if (isset($permissions[CFS_METHODS]) && is_array($permissions[CFS_METHODS])) { 340 foreach ($permissions[CFS_METHODS] as $method => $levels) { 341 if (strtolower($method) == $action) { 342 $res[] = (array) $levels; 343 break; 344 } 345 } 346 } 347 if (isset($permissions[CFS_USERLEVELS]) && is_array($permissions[CFS_USERLEVELS])) { 348 foreach ($permissions[CFS_USERLEVELS] as $userlevel => $methods) { 349 if ($this->_methodListed($action, (array) $methods)) { 350 $res[] = [$userlevel]; 351 break; 269 352 } 270 353 } … … 335 418 case 'ajax': 336 419 add_action('wp_ajax_' . $this->_action, [$mod->getController(), $this->_action]); 337 add_action('wp_ajax_nopriv_' . $this->_action, [$mod->getController(), $this->_action]); 420 // Not logged in visitors can reach only actions that controller declared as public 421 if ($this->isPublicAction($this->_mod, $this->_action)) { 422 add_action('wp_ajax_nopriv_' . $this->_action, [$mod->getController(), $this->_action]); 423 } 338 424 break; 339 425 default: -
contact-form-by-supsystic/trunk/classes/utils.php
r3679442 r3759933 735 735 } 736 736 return $str; 737 } 738 /** 739 * Make value safe to be placed in email header: line breaks there start new header. 740 * @param mixed $value Header value, or array of values 741 * @return mixed 742 */ 743 public static function cleanMailHeader($value) 744 { 745 if (is_array($value)) { 746 return array_map([__CLASS__, 'cleanMailHeader'], $value); 747 } 748 if (!is_scalar($value)) { 749 return ''; 750 } 751 return trim(preg_replace('/[\r\n\t\0\x0B\x0C]+/', ' ', (string) $value)); 752 } 753 /** 754 * Sendmail path is passed to shell by mailer, so allow only absolute path to sendmail-compatible binary, 755 * with few safe flags. 756 * @param string $path 757 * @return bool 758 */ 759 public static function isValidSendmailPath($path) 760 { 761 if (!is_string($path)) { 762 return false; 763 } 764 $path = trim($path, ' '); 765 if ($path === '') { 766 return true; // Default from php.ini will be used 767 } 768 // Only printable chars, parts are separated by spaces only 769 if (preg_match('/[^\x20-\x7E]/', $path)) { 770 return false; 771 } 772 $parts = preg_split('/ +/', $path); 773 $bin = array_shift($parts); 774 if (!preg_match('#^(?:[A-Za-z]:)?[\\\\/][A-Za-z0-9._\\\\/-]+$#', $bin) || strpos($bin, '..') !== false) { 775 return false; 776 } 777 $binName = basename(str_replace('\\', '/', $bin)); 778 if (!preg_match('/^(sendmail|msmtp|ssmtp|esmtp|exim4?|qmail-inject|mini_sendmail|nullmailer-inject)(\.exe)?$/i', $binName)) { 779 return false; 780 } 781 $emailRe = '/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+$/'; 782 for ($i = 0; $i < count($parts); $i++) { 783 $flag = $parts[$i]; 784 if (in_array($flag, ['-t', '-i', '-oi', '-ti'], true)) { 785 continue; 786 } 787 if (strpos($flag, '-f') === 0 && strlen($flag) > 2 && preg_match($emailRe, substr($flag, 2))) { 788 continue; 789 } 790 if ($flag === '-f' && isset($parts[$i + 1]) && preg_match($emailRe, $parts[$i + 1])) { 791 $i++; 792 continue; 793 } 794 return false; 795 } 796 return true; 737 797 } 738 798 public static function encodeArrayTxt($arr, $forceOrd = false) -
contact-form-by-supsystic/trunk/config.php
r3750170 r3759933 53 53 54 54 define('CFS_PLUGIN_INSTALLED', true); 55 define('CFS_VERSION', '1.1 0.7');55 define('CFS_VERSION', '1.11.1'); 56 56 define('CFS_USER', 'user'); 57 57 -
contact-form-by-supsystic/trunk/js/core.js
r3491826 r3759933 84 84 var dataType = params.dataType ? params.dataType : 'json'; 85 85 // Set plugin orientation 86 // Admin actions require plugin nonce - add it if request does not have it's own one 87 var adminNonce = cfsGetAdminNonce(); 86 88 if (typeof data == 'string') { 87 89 data += '&pl=' + CFS_DATA.CFS_CODE; 88 90 data += '&reqType=ajax'; 91 if (adminNonce && !/(^|&)_wpnonce=/.test(data)) data += '&_wpnonce=' + encodeURIComponent(adminNonce); 89 92 } else { 90 93 data['pl'] = CFS_DATA.CFS_CODE; 91 94 data['reqType'] = 'ajax'; 95 if (adminNonce && typeof data['_wpnonce'] == 'undefined') data['_wpnonce'] = adminNonce; 92 96 } 93 97 … … 194 198 } 195 199 200 /** 201 * Plugin nonce for admin requests, it is not available on frontend 202 */ 203 function cfsGetAdminNonce() { 204 if (typeof CFS_NONCE != 'undefined' && CFS_NONCE && CFS_NONCE.cfs_nonce) return CFS_NONCE.cfs_nonce; 205 if (typeof CFS_DATA != 'undefined' && CFS_DATA && CFS_DATA.cfsNonce) return CFS_DATA.cfsNonce; 206 return false; 207 } 196 208 function getDialogElementCfs() { 197 209 return jQuery('<div/>').appendTo(jQuery('body')); -
contact-form-by-supsystic/trunk/js/core.min.js
r3403065 r3759933 1 1 2 if(typeof(CFS_DATA)=="undefined"){var CFS_DATA={}}if(isNumber(CFS_DATA.animationSpeed)){CFS_DATA.animationSpeed=parseInt(CFS_DATA.animationSpeed)}else{if(jQuery.inArray(CFS_DATA.animationSpeed,["fast","slow"])==-1){CFS_DATA.animationSpeed="fast"}}CFS_DATA.showSubscreenOnCenter=parseInt(CFS_DATA.showSubscreenOnCenter);var sdLoaderImgCfs='<img src="'+CFS_DATA.loader+'" />';var g_cfsAnimationSpeed=300;jQuery.fn.showLoaderCfs=function(){return jQuery(this).html(sdLoaderImgCfs)};jQuery.fn.appendLoaderCfs=function(){jQuery(this).append(sdLoaderImgCfs)};jQuery.sendFormCfs=function(a){return jQuery("<br />").sendFormCfs(a)};jQuery.fn.sendFormCfs=function(e){var b=null;if(!e){e={fid:false,msgElID:false,onSuccess:false}}if(e.fid){b=jQuery("#"+fid)}else{b=jQuery(this)}var c=(jQuery(b).tagName()=="FORM");var f=new Array();if(e.data){f=e.data}else{if(c){f=jQuery(b).serialize()}}if(e.appendData){var h=typeof(f)=="string";var k=[];for(var g in e.appendData){if(h){k.push(g+"="+e.appendData[g])}else{f[g]=e.appendData[g]}}if(h){f+="&"+k.join("&")}}var d=null;if(e.msgElID){if(e.msgElID=="noMessages"){d=false}else{if(typeof(e.msgElID)=="object"){d=e.msgElID}else{d=jQuery("#"+e.msgElID)}}}if(typeof(e.inputsWraper)=="string"){b=jQuery("#"+e.inputsWraper);c=true}if(c&&b){jQuery(b).find("*").removeClass("cfsInputError")}if(d&&!e.btn){jQuery(d).removeClass("cfsSuccessMsg").removeClass("cfsErrorMsg");if(!e.btn){jQuery(d).showLoaderCfs()}}if(e.btn){jQuery(e.btn).attr("disabled","disabled");e.btnIconElement=jQuery(e.btn).find(".fa").length?jQuery(e.btn).find(".fa"):jQuery(e.btn);if(jQuery(e.btn).find(".fa").length){e.btnIconElement.data("prev-class",e.btnIconElement.attr("class")).attr("class","fa fa-spinner fa-spin")}}var a="";if(typeof(e.url)!="undefined"){a=e.url}else{if(typeof(ajaxurl)=="undefined"){a=CFS_DATA.ajaxurl}else{a=ajaxurl}}jQuery(".cfsErrorForField").hide(CFS_DATA.animationSpeed);var j=e.dataType?e.dataType:"json"; if(typeof(f)=="string"){f+="&pl="+CFS_DATA.CFS_CODE;f+="&reqType=ajax"}else{f.pl=CFS_DATA.CFS_CODE;f.reqType="ajax"}jQuery.ajax({url:a,data:f,type:"POST",dataType:j,success:function(i){toeProcessAjaxResponseCfs(i,d,b,c,e);if(e.clearMsg){setTimeout(function(){if(d){jQuery(d).animateClear()}},typeof(e.clearMsg)=="boolean"?5000:e.clearMsg)}}})};jQuery.fn.animateClear=function(){var a=jQuery("<span>"+jQuery(this).html()+"</span>");jQuery(this).html(a);jQuery(a).hide(CFS_DATA.animationSpeed,function(){jQuery(a).remove()})};jQuery.fn.animateRemoveCfs=function(a,b){a=a==undefined?CFS_DATA.animationSpeed:a;jQuery(this).hide(a,function(){jQuery(this).remove();if(typeof(b)==="function"){b()}})};function toeProcessAjaxResponseCfs(h,e,c,d,f){if(typeof(f)=="undefined"){f={}}if(typeof(e)=="string"){e=jQuery("#"+e)}if(e){jQuery(e).html("")}if(f.btn){jQuery(f.btn).removeAttr("disabled");if(f.btnIconElement){f.btnIconElement.attr("class",f.btnIconElement.data("prev-class"))}}if(typeof(h)=="object"){if(h.error){if(e){jQuery(e).removeClass("cfsSuccessMsg").addClass("cfsErrorMsg")}var j=[];for(var a in h.errors){if(d){var b=jQuery(c).find('[name*="'+a+'"]');b.addClass("cfsInputError");if(b.attr("placeholder")){}if(!b.data("keyup-error-remove-binded")){b.keydown(function(){jQuery(this).removeClass("cfsInputError")}).data("keyup-error-remove-binded",1)}}if(jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").exists()){jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").show().html(h.errors[a])}else{if(e){jQuery(e).append(h.errors[a]).append("<br />")}else{j.push(h.errors[a])}}}if(j.length&&f.btn&&jQuery.fn.dialog&&!e){jQuery('<div title="'+toeLangCfs("Really small warning :)")+'" />').html(j.join("<br />")).appendTo("body").dialog({modal:true,width:"500px"})}}else{if(h.messages.length){if(e){jQuery(e).removeClass("cfsErrorMsg").addClass("cfsSuccessMsg");for(var g=0;g<h.messages.length;g++){jQuery(e).append(h.messages[g]).append("<br />")}}}}}if(f.onSuccess&&typeof(f.onSuccess)=="function"){f.onSuccess(h)}}function getDialogElementCfs(){return jQuery("<div/>").appendTo(jQuery("body"))}function toeOptionCfs(a){if(CFS_DATA.options&&CFS_DATA.options[a]){return CFS_DATA.options[a]}return false}function toeLangCfs(a){if(CFS_DATA.siteLang&&CFS_DATA.siteLang[a]){return CFS_DATA.siteLang[a]}return a}function toePagesCfs(a){if(typeof(CFS_DATA)!="undefined"&&CFS_DATA[a]){return CFS_DATA[a]}return false}function toeOptTimeoutHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");setTimeout(function(){if(!jQuery("#cfsOptDescription").attr("toeFixTip")){toeOptHideDescriptionCfs()}},500)}function toeOptShowDescriptionCfs(b,a,d,c){if(typeof(b)!="undefined"&&b!=""){if(!jQuery("#cfsOptDescription").length){jQuery("body").append('<div id="cfsOptDescription"></div>')}if(c){jQuery("#cfsOptDescription").css("right",jQuery(window).width()-(a-10))}else{jQuery("#cfsOptDescription").css("left",a+10)}jQuery("#cfsOptDescription").css("top",d);jQuery("#cfsOptDescription").show(200);jQuery("#cfsOptDescription").html(b)}}function toeOptHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");jQuery("#cfsOptDescription").hide(200)}function toeInArrayCfs(c,b){if(b){for(var a in b){if(b[a]==c){return true}}}return false}function toeShowDialogCustomized(b,a){a=jQuery.extend({resizable:false,width:500,height:300,closeOnEscape:true,open:function(c,d){jQuery(".ui-dialog-titlebar").css({"background-color":"#222222","background-image":"none",border:"none",margin:"0",padding:"0","border-radius":"0",color:"#CFCFCF",height:"27px"});jQuery(".ui-dialog-titlebar-close").css({background:'url("'+CFS_DATA.cssPath+'img/tb-close.png") no-repeat scroll 0 0 transparent',border:"0",width:"15px",height:"15px",padding:"0","border-radius":"0",margin:"7px 7px 0"}).html("");jQuery(".ui-dialog").css({"border-radius":"3px","background-color":"#FFFFFF","background-image":"none",padding:"1px","z-index":"300000",position:"fixed",top:"60px"});jQuery(".ui-dialog-buttonpane").css({"background-color":"#FFFFFF"});jQuery(".ui-dialog-title").css({color:"#CFCFCF",font:"12px sans-serif",padding:"6px 10px 0"});if(a.openCallback&&typeof(a.openCallback)=="function"){a.openCallback(c,d)}jQuery(".ui-widget-overlay").css({"z-index":jQuery(c.target).parents(".ui-dialog:first").css("z-index")-1,"background-image":"none"});if(a.modal&&a.closeOnBg){jQuery(".ui-widget-overlay").unbind("click").bind("click",function(){jQuery(b).dialog("close")})}}},a);return jQuery(b).dialog(a)}function toeSliderMove(a,b){var c=jQuery(a.target).attr("id");jQuery("#toeSliderDisplay_"+c).html(b.value);jQuery("#toeSliderInput_"+c).val(b.value).change()}function cfsCorrectJqueryUsed(){return(typeof(jQuery.fn.sendFormCfs)==="function")}function cfsReloadCoreJs(d,e){var c="",b=["common.js","core.js"];for(var a=0;a<b.length;a++){c+='<script type="text/javascript" class="cfsReloadedScript" src="'+CFS_DATA.jsPath+b[a]+'"><\/script>'}jQuery("head").append(c);if(d){_cfsRunClbAfterCoreReload(d,e)}}function _cfsRunClbAfterCoreReload(a,b){if(cfsCorrectJqueryUsed()){callUserFuncArray(a,b);return}setTimeout(function(){cfsCorrectJqueryUsed(a,b)},500)}function base64_decode(d){var b="";var l,j,g="";var k,h,f,e="";var c=0;var a=/[^A-Za-z0-9\+\/\=]/g;if(a.exec(d)){alert("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding.")}d=d.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{k=keyStr.indexOf(d.charAt(c++));h=keyStr.indexOf(d.charAt(c++));f=keyStr.indexOf(d.charAt(c++));e=keyStr.indexOf(d.charAt(c++));l=(k<<2)|(h>>4);j=((h&15)<<4)|(f>>2);g=((f&3)<<6)|e;b=b+String.fromCharCode(l);if(f!=64){b=b+String.fromCharCode(j)}if(e!=64){b=b+String.fromCharCode(g)}l=j=g="";k=h=f=e=""}while(c<d.length);return unescape(b)};2 if(typeof(CFS_DATA)=="undefined"){var CFS_DATA={}}if(isNumber(CFS_DATA.animationSpeed)){CFS_DATA.animationSpeed=parseInt(CFS_DATA.animationSpeed)}else{if(jQuery.inArray(CFS_DATA.animationSpeed,["fast","slow"])==-1){CFS_DATA.animationSpeed="fast"}}CFS_DATA.showSubscreenOnCenter=parseInt(CFS_DATA.showSubscreenOnCenter);var sdLoaderImgCfs='<img src="'+CFS_DATA.loader+'" />';var g_cfsAnimationSpeed=300;jQuery.fn.showLoaderCfs=function(){return jQuery(this).html(sdLoaderImgCfs)};jQuery.fn.appendLoaderCfs=function(){jQuery(this).append(sdLoaderImgCfs)};jQuery.sendFormCfs=function(a){return jQuery("<br />").sendFormCfs(a)};jQuery.fn.sendFormCfs=function(e){var b=null;if(!e){e={fid:false,msgElID:false,onSuccess:false}}if(e.fid){b=jQuery("#"+fid)}else{b=jQuery(this)}var c=(jQuery(b).tagName()=="FORM");var f=new Array();if(e.data){f=e.data}else{if(c){f=jQuery(b).serialize()}}if(e.appendData){var h=typeof(f)=="string";var k=[];for(var g in e.appendData){if(h){k.push(g+"="+e.appendData[g])}else{f[g]=e.appendData[g]}}if(h){f+="&"+k.join("&")}}var d=null;if(e.msgElID){if(e.msgElID=="noMessages"){d=false}else{if(typeof(e.msgElID)=="object"){d=e.msgElID}else{d=jQuery("#"+e.msgElID)}}}if(typeof(e.inputsWraper)=="string"){b=jQuery("#"+e.inputsWraper);c=true}if(c&&b){jQuery(b).find("*").removeClass("cfsInputError")}if(d&&!e.btn){jQuery(d).removeClass("cfsSuccessMsg").removeClass("cfsErrorMsg");if(!e.btn){jQuery(d).showLoaderCfs()}}if(e.btn){jQuery(e.btn).attr("disabled","disabled");e.btnIconElement=jQuery(e.btn).find(".fa").length?jQuery(e.btn).find(".fa"):jQuery(e.btn);if(jQuery(e.btn).find(".fa").length){e.btnIconElement.data("prev-class",e.btnIconElement.attr("class")).attr("class","fa fa-spinner fa-spin")}}var a="";if(typeof(e.url)!="undefined"){a=e.url}else{if(typeof(ajaxurl)=="undefined"){a=CFS_DATA.ajaxurl}else{a=ajaxurl}}jQuery(".cfsErrorForField").hide(CFS_DATA.animationSpeed);var j=e.dataType?e.dataType:"json";var n=cfsGetAdminNonce();if(typeof(f)=="string"){f+="&pl="+CFS_DATA.CFS_CODE;f+="&reqType=ajax";if(n&&!/(^|&)_wpnonce=/.test(f)){f+="&_wpnonce="+encodeURIComponent(n)}}else{f.pl=CFS_DATA.CFS_CODE;f.reqType="ajax";if(n&&typeof(f._wpnonce)=="undefined"){f._wpnonce=n}}jQuery.ajax({url:a,data:f,type:"POST",dataType:j,success:function(i){toeProcessAjaxResponseCfs(i,d,b,c,e);if(e.clearMsg){setTimeout(function(){if(d){jQuery(d).animateClear()}},typeof(e.clearMsg)=="boolean"?5000:e.clearMsg)}}})};jQuery.fn.animateClear=function(){var a=jQuery("<span>"+jQuery(this).html()+"</span>");jQuery(this).html(a);jQuery(a).hide(CFS_DATA.animationSpeed,function(){jQuery(a).remove()})};jQuery.fn.animateRemoveCfs=function(a,b){a=a==undefined?CFS_DATA.animationSpeed:a;jQuery(this).hide(a,function(){jQuery(this).remove();if(typeof(b)==="function"){b()}})};function toeProcessAjaxResponseCfs(h,e,c,d,f){if(typeof(f)=="undefined"){f={}}if(typeof(e)=="string"){e=jQuery("#"+e)}if(e){jQuery(e).html("")}if(f.btn){jQuery(f.btn).removeAttr("disabled");if(f.btnIconElement){f.btnIconElement.attr("class",f.btnIconElement.data("prev-class"))}}if(typeof(h)=="object"){if(h.error){if(e){jQuery(e).removeClass("cfsSuccessMsg").addClass("cfsErrorMsg")}var j=[];for(var a in h.errors){if(d){var b=jQuery(c).find('[name*="'+a+'"]');b.addClass("cfsInputError");if(b.attr("placeholder")){}if(!b.data("keyup-error-remove-binded")){b.keydown(function(){jQuery(this).removeClass("cfsInputError")}).data("keyup-error-remove-binded",1)}}if(jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").exists()){jQuery(".cfsErrorForField.toe_"+nameToClassId(a)+"").show().html(h.errors[a])}else{if(e){jQuery(e).append(h.errors[a]).append("<br />")}else{j.push(h.errors[a])}}}if(j.length&&f.btn&&jQuery.fn.dialog&&!e){jQuery('<div title="'+toeLangCfs("Really small warning :)")+'" />').html(j.join("<br />")).appendTo("body").dialog({modal:true,width:"500px"})}}else{if(h.messages.length){if(e){jQuery(e).removeClass("cfsErrorMsg").addClass("cfsSuccessMsg");for(var g=0;g<h.messages.length;g++){jQuery(e).append(h.messages[g]).append("<br />")}}}}}if(f.onSuccess&&typeof(f.onSuccess)=="function"){f.onSuccess(h)}}function cfsGetAdminNonce(){if(typeof(CFS_NONCE)!="undefined"&&CFS_NONCE&&CFS_NONCE.cfs_nonce){return CFS_NONCE.cfs_nonce}if(typeof(CFS_DATA)!="undefined"&&CFS_DATA&&CFS_DATA.cfsNonce){return CFS_DATA.cfsNonce}return false}function getDialogElementCfs(){return jQuery("<div/>").appendTo(jQuery("body"))}function toeOptionCfs(a){if(CFS_DATA.options&&CFS_DATA.options[a]){return CFS_DATA.options[a]}return false}function toeLangCfs(a){if(CFS_DATA.siteLang&&CFS_DATA.siteLang[a]){return CFS_DATA.siteLang[a]}return a}function toePagesCfs(a){if(typeof(CFS_DATA)!="undefined"&&CFS_DATA[a]){return CFS_DATA[a]}return false}function toeOptTimeoutHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");setTimeout(function(){if(!jQuery("#cfsOptDescription").attr("toeFixTip")){toeOptHideDescriptionCfs()}},500)}function toeOptShowDescriptionCfs(b,a,d,c){if(typeof(b)!="undefined"&&b!=""){if(!jQuery("#cfsOptDescription").length){jQuery("body").append('<div id="cfsOptDescription"></div>')}if(c){jQuery("#cfsOptDescription").css("right",jQuery(window).width()-(a-10))}else{jQuery("#cfsOptDescription").css("left",a+10)}jQuery("#cfsOptDescription").css("top",d);jQuery("#cfsOptDescription").show(200);jQuery("#cfsOptDescription").html(b)}}function toeOptHideDescriptionCfs(){jQuery("#cfsOptDescription").removeAttr("toeFixTip");jQuery("#cfsOptDescription").hide(200)}function toeInArrayCfs(c,b){if(b){for(var a in b){if(b[a]==c){return true}}}return false}function toeShowDialogCustomized(b,a){a=jQuery.extend({resizable:false,width:500,height:300,closeOnEscape:true,open:function(c,d){jQuery(".ui-dialog-titlebar").css({"background-color":"#222222","background-image":"none",border:"none",margin:"0",padding:"0","border-radius":"0",color:"#CFCFCF",height:"27px"});jQuery(".ui-dialog-titlebar-close").css({background:'url("'+CFS_DATA.cssPath+'img/tb-close.png") no-repeat scroll 0 0 transparent',border:"0",width:"15px",height:"15px",padding:"0","border-radius":"0",margin:"7px 7px 0"}).html("");jQuery(".ui-dialog").css({"border-radius":"3px","background-color":"#FFFFFF","background-image":"none",padding:"1px","z-index":"300000",position:"fixed",top:"60px"});jQuery(".ui-dialog-buttonpane").css({"background-color":"#FFFFFF"});jQuery(".ui-dialog-title").css({color:"#CFCFCF",font:"12px sans-serif",padding:"6px 10px 0"});if(a.openCallback&&typeof(a.openCallback)=="function"){a.openCallback(c,d)}jQuery(".ui-widget-overlay").css({"z-index":jQuery(c.target).parents(".ui-dialog:first").css("z-index")-1,"background-image":"none"});if(a.modal&&a.closeOnBg){jQuery(".ui-widget-overlay").unbind("click").bind("click",function(){jQuery(b).dialog("close")})}}},a);return jQuery(b).dialog(a)}function toeSliderMove(a,b){var c=jQuery(a.target).attr("id");jQuery("#toeSliderDisplay_"+c).html(b.value);jQuery("#toeSliderInput_"+c).val(b.value).change()}function cfsCorrectJqueryUsed(){return(typeof(jQuery.fn.sendFormCfs)==="function")}function cfsReloadCoreJs(d,e){var c="",b=["common.js","core.js"];for(var a=0;a<b.length;a++){c+='<script type="text/javascript" class="cfsReloadedScript" src="'+CFS_DATA.jsPath+b[a]+'"><\/script>'}jQuery("head").append(c);if(d){_cfsRunClbAfterCoreReload(d,e)}}function _cfsRunClbAfterCoreReload(a,b){if(cfsCorrectJqueryUsed()){callUserFuncArray(a,b);return}setTimeout(function(){cfsCorrectJqueryUsed(a,b)},500)}function base64_decode(d){var b="";var l,j,g="";var k,h,f,e="";var c=0;var a=/[^A-Za-z0-9\+\/\=]/g;if(a.exec(d)){alert("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding.")}d=d.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{k=keyStr.indexOf(d.charAt(c++));h=keyStr.indexOf(d.charAt(c++));f=keyStr.indexOf(d.charAt(c++));e=keyStr.indexOf(d.charAt(c++));l=(k<<2)|(h>>4);j=((h&15)<<4)|(f>>2);g=((f&3)<<6)|e;b=b+String.fromCharCode(l);if(f!=64){b=b+String.fromCharCode(j)}if(e!=64){b=b+String.fromCharCode(g)}l=j=g="";k=h=f=e=""}while(c<d.length);return unescape(b)}; -
contact-form-by-supsystic/trunk/modules/forms/controller.php
r3679442 r3759933 622 622 return ['save', 'removeGroup', 'getListForTbl', 'saveAsCopy', 'remove', 'createFromTpl', 'changeTpl']; 623 623 } 624 /** 625 * contact() checks it's own per-form nonce, updateNonce() just gives fresh nonce for cached pages 626 */ 627 public function getPublicMethods() 628 { 629 return ['contact', 'updateNonce']; 630 } 624 631 public function getPermissions() 625 632 { -
contact-form-by-supsystic/trunk/modules/forms/models/forms.php
r3640942 r3759933 204 204 } 205 205 if (empty($errorMsg)) { 206 // Not mandatory email can be empty, but if it is entered - it must be valid 207 if ($htmlType == 'email' && $value && (!is_string($value) || !is_email($value))) { 208 $errorMsg = empty($formInvalidError) ? __('Invalid value for %s', CFS_LANG_CODE) : $formInvalidError; 209 } 210 } 211 if (empty($errorMsg)) { 206 212 // Start other validation process 207 213 if (!$isDate && isset($f['min_size']) && !empty($f['min_size']) && ($minSize = (int) $f['min_size'])) { … … 315 321 // This is requiredfor case when you hav select box with vals = mail1@mail.com, ... and names User Name 1, ... 316 322 // To send to it's values, not to it's names 317 $variablesWithSelectVals['user_' . $sendName] = $ fieldsData[$sendName];323 $variablesWithSelectVals['user_' . $sendName] = $this->_getSelectedOptionValue($f, isset($fieldsData[$sendName]) ? $fieldsData[$sendName] : ''); 318 324 break; 319 325 default: … … 324 330 } 325 331 } 332 // Submitted values can be mapped to mail headers - line breaks there would start new headers 333 $headerVariables = utilsCfs::cleanMailHeader($variables); 334 $headerVariablesWithSelectVals = utilsCfs::cleanMailHeader($variablesWithSelectVals); 326 335 $sendForceTo = dispatcherCfs::applyFilters('sendContactTo', '', $fieldsData, $form); 327 336 foreach ($form['params']['submit'] as $s) { … … 334 343 $additionalHeaders = []; 335 344 if (isset($s['enb_cc']) && (int) $s['enb_cc'] && isset($s['cc']) && !empty($s['cc'])) { 336 $additionalHeaders[] = 'Cc: ' . utilsCfs:: replaceVariables($s['cc'], $variables);345 $additionalHeaders[] = 'Cc: ' . utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['cc'], $headerVariables)); 337 346 } 338 347 if (isset($s['from']) && !empty($s['from'])) { 339 $additionalHeaders[] = 'From: ' . utilsCfs:: replaceVariables($s['from'], $variables);348 $additionalHeaders[] = 'From: ' . utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['from'], $headerVariables)); 340 349 } 341 350 if (isset($s['reply']) && !empty($s['reply'])) { 342 $additionalHeaders[] = 'Reply-To: ' . utilsCfs::replaceVariables($s['reply'], $variables); 343 } 344 $to = utilsCfs::replaceVariables($to, $variablesWithSelectVals); 345 $subject = utilsCfs::replaceVariables($s['subject'], $variables); 351 $additionalHeaders[] = 'Reply-To: ' . utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['reply'], $headerVariables)); 352 } 353 $to = utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($to, $headerVariablesWithSelectVals)); 354 if (empty($to)) { 355 continue; // Recipient was taken from submitted data, and it was not valid 356 } 357 $subject = utilsCfs::cleanMailHeader(utilsCfs::replaceVariables($s['subject'], $headerVariables)); 346 358 // Let it be only for Message field 347 359 //$msg = nl2br(utilsCfs::replaceVariables($msg, array_merge($variables, array('form_data' => $sendFormDataStr)))); … … 363 375 } 364 376 return true; 377 } 378 /** 379 * Submitted select box value can be used as recipient email, @see sendContact(), 380 * so it is accepted only if it is one of field options 381 * @param array $field Select box field 382 * @param mixed $value Submitted value 383 * @return string Value, or empty string if there is no such option 384 */ 385 private function _getSelectedOptionValue($field, $value) 386 { 387 if (!is_string($value) || $value === '' || empty($field['options']) || !is_array($field['options'])) { 388 return ''; 389 } 390 // Options are prepared in same way as submitted data, @see contact() 391 foreach (dbCfs::prepareHtmlIn($field['options']) as $opt) { 392 if (isset($opt['name']) && (string) $opt['name'] === $value) { 393 return $value; 394 } 395 } 396 return ''; 365 397 } 366 398 private function _generateSendFormData($fieldsData, $form) … … 782 814 for ($i = 0; $i < (int) $d['params']['opts_attrs']['txt_block_number']; $i++) { 783 815 $sendValKey = 'params_tpl_txt_val_' . $i; 784 if (isset($d[$sendValKey])) { 785 $d['params']['tpl']['txt_' . $i] = urldecode($d[$sendValKey]); 816 if (isset($d[$sendValKey]) && is_string($d[$sendValKey])) { 817 // Text is sent url-encoded, so request filter did not see real value - filter it after decode 818 $d['params']['tpl']['txt_' . $i] = reqCfs::sanitizeString(urldecode($d[$sendValKey])); 786 819 } 787 820 } -
contact-form-by-supsystic/trunk/modules/forms/views/forms.php
r3750170 r3759933 5 5 { 6 6 protected $_twig; 7 /** 8 * Tags values for current render: placeholder => value, @see _addTwigValue() 9 */ 10 private $_twigValues = []; 11 private $_twigValuesKey = ''; 7 12 private $_renderFormIter = 0; 8 13 private $_lastForm = null; … … 14 19 frameCfs::_()->addScript('admin.forms', $this->getModule()->getModPath() . 'js/admin.forms.js'); 15 20 frameCfs::_()->addScript('admin.forms.list', $this->getModule()->getModPath() . 'js/admin.forms.list.js'); 16 frameCfs::_()->addJSVar('admin.forms.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getListForTbl', ['reqType' => 'ajax' ]));21 frameCfs::_()->addJSVar('admin.forms.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getListForTbl', ['reqType' => 'ajax', '_wpnonce' => wp_create_nonce('cfs_nonce')])); 17 22 18 23 $this->assign('addNewLink', frameCfs::_()->getModule('options')->getTabUrl('forms_add_new')); … … 114 119 ]; 115 120 116 $this->assign('csvExportUrl', uriCfs::mod('forms', 'exportCsv', ['id' => $id ]));121 $this->assign('csvExportUrl', uriCfs::mod('forms', 'exportCsv', ['id' => $id, '_wpnonce' => wp_create_nonce('cfs_nonce')])); 117 122 118 123 $this->assign('adminEmail', get_bloginfo('admin_email')); … … 123 128 $this->assign('cfsAddNewUrl', $cfsAddNewUrl); 124 129 $this->assign('bgTypes', $bgType); 125 $this->assign('previewUrl', uriCfs::mod('forms', 'getPreviewHtml', ['id' => $id ]));130 $this->assign('previewUrl', uriCfs::mod('forms', 'getPreviewHtml', ['id' => $id, '_wpnonce' => wp_create_nonce('cfs_nonce')])); 126 131 $this->assign('form', $form); 127 132 $this->assign('fieldTypes', $fieldTypes); … … 473 478 public function adjustOpacity($color, $alpha) 474 479 { 480 $color = $this->_resolveTwigValues($color); 481 $alpha = $this->_resolveTwigValues($alpha); 475 482 $alpha = max(0, min(1, $alpha)); 476 483 $rgbColor = utilsCfs::hexToRgb($color); … … 478 485 return 'rgba(' . implode(',', $rgbColor) . ')'; 479 486 } 487 public function hexToRgbaStr($hex, $alpha = 1) 488 { 489 return utilsCfs::hexToRgbaStr($this->_resolveTwigValues($hex), $this->_resolveTwigValues($alpha)); 490 } 480 491 public function adjustBrightness($hex, $steps) 481 492 { 493 $hex = $this->_resolveTwigValues($hex); 494 $steps = $this->_resolveTwigValues($steps); 482 495 // Steps should be between -255 and 255. Negative = darker, positive = lighter 483 496 $steps = max(-255, min(255, $steps)); … … 525 538 526 539 $form['css'] = $this->_replaceTagsWithTwig($form['css'], $form); 540 $htmlValuesFrom = count($this->_twigValues); 527 541 $form['html'] = $this->_replaceTagsWithTwig($form['html'], $form); 528 542 529 $form['html'] = str_replace('col-md-', 'supMd', $form['html']); 530 $form['html'] = str_replace('col-xs-', 'supXs', $form['html']); 531 $form['html'] = str_replace('col-sm-', 'supSm', $form['html']); 532 $form['html'] = str_replace('col-lg-', 'supLg', $form['html']); 533 $form['html'] = str_replace('row', 'supRow', $form['html']); 543 $colReplaceFrom = ['col-md-', 'col-xs-', 'col-sm-', 'col-lg-', 'row']; 544 $colReplaceTo = ['supMd', 'supXs', 'supSm', 'supLg', 'supRow']; 545 $form['html'] = str_replace($colReplaceFrom, $colReplaceTo, $form['html']); 546 // Values of tags in html were always processed by this replacement too 547 foreach (array_slice(array_keys($this->_twigValues), $htmlValuesFrom) as $valueKey) { 548 $this->_twigValues[$valueKey] = str_replace($colReplaceFrom, $colReplaceTo, $this->_twigValues[$valueKey]); 549 } 534 550 535 551 $form['html'] .= $this->_generateImgsPreload($form); … … 540 556 // it will not recognize css in js data as style whye rendering on server side, 541 557 // but will be replaced back to normal <style> tag in JS, @see js/frontend.forms.js 542 return $this->_twig->render(558 $tpl = 543 559 ($replaceStyleTag ? '<span style="display: none;" id="cfsFormStylesHidden_' . $form['view_id'] . '">' : '<style type="text/css" id="' . $form['view_html_id'] . '_style">') . 544 $form['css'] . 545 ($replaceStyleTag ? '</span>' : '</style>') . 546 '<div id="' . 547 $form['view_html_id'] . 548 '" class="cfsFormShell">' . 549 $form['html'] . 550 '</div>', 551 ['forms' => $form], 552 ); 560 $form['css'] . 561 ($replaceStyleTag ? '</span>' : '</style>') . 562 '<div id="' . 563 $form['view_html_id'] . 564 '" class="cfsFormShell">' . 565 $form['html'] . 566 '</div>'; 567 $obLevel = ob_get_level(); 568 try { 569 $res = $this->_twig->render($tpl, ['forms' => $form]); 570 } catch (Throwable $e) { 571 // Twig cleans own output buffer only for exceptions, not for PHP errors 572 while (ob_get_level() > $obLevel) { 573 ob_end_clean(); 574 } 575 // String loader uses whole template as it's name - so full Twig message would contain all template 576 $errorMsg = $e instanceof Twig_Error ? $e->getRawMessage() : $e->getMessage(); 577 error_log('Contact Form by Supsystic: can not render form #' . $form['id'] . ': ' . $errorMsg); 578 return frameCfs::_()->getModule('user')->isAdmin() ? esc_html(sprintf(__('Can not render form template: %s', CFS_LANG_CODE), $errorMsg)) : ''; 579 } 580 // Put tags values only now - so they are never parsed by template engine 581 return $this->_insertTwigValues($res); 553 582 } 554 583 private function _generateCommonFormCss($form) 555 584 { 556 585 $res = ''; 557 $res .= '#[SHELL_ID] { width: ' . $form['params']['tpl']['width'] . $form['params']['tpl']['width_measure'] . '}'; 586 // Values go through tags too, @see _replaceTagsWithTwig() 587 $res .= '#[SHELL_ID] { width: ' . (isset($form['params']['tpl']['width']) ? '[width]' : '') . (isset($form['params']['tpl']['width_measure']) ? '[width_measure]' : '') . '}'; 558 588 if (isset($form['params'], $form['params']['tpl'], $form['params']['tpl']['form_sent_msg_color']) && !empty($form['params']['tpl']['form_sent_msg_color'])) { 559 $res .= '#[SHELL_ID] .cfsSuccessMsg { color: ' . $form['params']['tpl']['form_sent_msg_color'] . '!important}';589 $res .= '#[SHELL_ID] .cfsSuccessMsg { color: [form_sent_msg_color] !important}'; 560 590 } 561 591 return $res; … … 863 893 foreach ($replaceFrom as $i => $v) { 864 894 $replaceFrom[$i] = '[' . $v . ']'; 895 // Tags values are users data: put them in template only as placeholders, real values are inserted 896 // after template render, so they are never evaluated by template engine. First 4 tags - are template syntax. 897 if ($i > 3) { 898 $replaceTo[$i] = $this->_addTwigValue($replaceTo[$i]); 899 } 865 900 } 866 901 return str_replace($replaceFrom, $replaceTo, $string); 902 } 903 /** 904 * Register value for template and get it's placeholder 905 * @param mixed $value 906 * @return string Placeholder: it is safe for any template place - text, or string in Twig expression 907 */ 908 private function _addTwigValue($value) 909 { 910 if (empty($this->_twigValuesKey)) { 911 // Unpredictable, and contains only chars that will not be changed by any template replacements 912 $this->_twigValuesKey = strtoupper(substr(md5(uniqid('', true) . wp_rand()), 0, 12)); 913 } 914 $placeholder = '__CFSV' . $this->_twigValuesKey . '_' . count($this->_twigValues) . '__'; 915 // Same line breaks normalization as Twig lexer did, when values were part of template 916 $this->_twigValues[$placeholder] = is_scalar($value) ? str_replace(["\r\n", "\r"], "\n", (string) $value) : ''; 917 return $placeholder; 918 } 919 private function _insertTwigValues($str) 920 { 921 // strtr() makes all replacements in one pass, so inserted values are not processed again 922 return empty($this->_twigValues) ? $str : strtr($str, $this->_twigValues); 923 } 924 /** 925 * Template functions get placeholders as arguments, @see adjustBrightness() 926 */ 927 private function _resolveTwigValues($value) 928 { 929 return is_string($value) && strpos($value, '__CFSV') !== false ? $this->_insertTwigValues($value) : $value; 867 930 } 868 931 protected function _initTwig() … … 873 936 } 874 937 Twig_Autoloader::register(); 938 importClassCfs('twigSecurityPolicyCfs', CFS_CLASSES_DIR . 'twigSecurityPolicy.php'); 875 939 $this->_twig = new Twig_Environment(new Twig_Loader_String(), ['debug' => 0]); 940 // Templates can be edited in admin area - so they are always rendered in sandbox 941 $this->_twig->addExtension(new Twig_Extension_Sandbox(new twigSecurityPolicyCfs(), true)); 876 942 $this->_twig->addFunction(new Twig_SimpleFunction('adjust_brightness', [$this, 'adjustBrightness'])); 877 943 $this->_twig->addFunction(new Twig_SimpleFunction('adjust_opacity', [$this, 'adjustOpacity'])); 878 $this->_twig->addFunction(new Twig_SimpleFunction('hex_to_rgba_str', 'utilsCfs::hexToRgbaStr'));944 $this->_twig->addFunction(new Twig_SimpleFunction('hex_to_rgba_str', [$this, 'hexToRgbaStr'])); 879 945 } 880 946 } … … 885 951 frameCfs::_()->addScript('admin.forms', $this->getModule()->getModPath() . 'js/admin.forms.js'); 886 952 frameCfs::_()->addScript('admin.forms.contacts.list', $this->getModule()->getModPath() . 'js/admin.forms.contacts.list.js'); 887 frameCfs::_()->addJSVar('admin.forms.contacts.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getContactsListForTbl', ['reqType' => 'ajax', 'fid' => $fid ]));953 frameCfs::_()->addJSVar('admin.forms.contacts.list', 'cfsTblDataUrl', uriCfs::mod('forms', 'getContactsListForTbl', ['reqType' => 'ajax', 'fid' => $fid, '_wpnonce' => wp_create_nonce('cfs_nonce')])); 888 954 $allForms = $this->getModel('forms')->getAllFromTbl(); 889 955 $allFormsForSelect = []; -
contact-form-by-supsystic/trunk/modules/forms/views/tpl/formsEditFormStatistics.php
r3491826 r3759933 39 39 <a href="#" class="button cfsStatChartGroupBtn" data-stat-group="month" data-chart="cfsMainStats"><?php _e('Month', CFS_LANG_CODE); ?></a> 40 40 | 41 <a href="<?php echo uriCfs::mod('statistics', 'getCsv' ); ?>" target="_blank" class="button cfsStatExportCsv" data-chart="cfsMainStats"><?php _e('Export to CSV', CFS_LANG_CODE); ?></a>41 <a href="<?php echo uriCfs::mod('statistics', 'getCsv', ['_wpnonce' => wp_create_nonce('cfs_nonce')]); ?>" target="_blank" class="button cfsStatExportCsv" data-chart="cfsMainStats"><?php _e('Export to CSV', CFS_LANG_CODE); ?></a> 42 42 | 43 43 </span> -
contact-form-by-supsystic/trunk/modules/mail/mod.php
r3491826 r3759933 7 7 public function send($to, $subject, $message, $fromName = '', $fromEmail = '', $replyToName = '', $replyToEmail = '', $additionalHeaders = [], $additionalParameters = []) 8 8 { 9 // Line breaks in any of header values would inject new mail headers 10 list($to, $subject, $fromName, $fromEmail, $replyToName, $replyToEmail) = utilsCfs::cleanMailHeader([$to, $subject, $fromName, $fromEmail, $replyToName, $replyToEmail]); 11 $additionalHeaders = empty($additionalHeaders) ? [] : array_filter(utilsCfs::cleanMailHeader((array) $additionalHeaders)); 9 12 $type = frameCfs::_()->getModule('options')->get('mail_send_engine'); 10 13 $res = false; … … 69 72 $this->_sendMailMailer = new PHPMailer\PHPMailer\PHPMailer(true); // create a new object 70 73 $this->_sendMailMailer->isSendmail(); // enable SendMail 71 $sendMailPath = trim(frameCfs::_()->getModule('options')->get('sendmail_path')); 72 if (!empty($sendMailPath)) { 74 $sendMailPath = trim((string) frameCfs::_()->getModule('options')->get('sendmail_path')); 75 // Value could be saved before validation was added - never pass invalid one to shell 76 if (!empty($sendMailPath) && utilsCfs::isValidSendmailPath($sendMailPath)) { 73 77 $this->_sendMailMailer->Sendmail = $sendMailPath; 74 78 } -
contact-form-by-supsystic/trunk/modules/mail/views/tpl/mailAdmin.php
r3491826 r3759933 6 6 <?php echo htmlCfs::hidden('mod', ['value' => 'mail']); ?> 7 7 <?php echo htmlCfs::hidden('action', ['value' => 'testEmail']); ?> 8 <?php echo htmlCfs::defaultNonceForAdminPanel(); ?> 8 9 <button class="button button-primary"> 9 10 <i class="fa fa-paper-plane"></i> … … 63 64 <?php echo htmlCfs::hidden('mod', ['value' => 'mail']); ?> 64 65 <?php echo htmlCfs::hidden('action', ['value' => 'saveOptions']); ?> 66 <?php echo htmlCfs::defaultNonceForAdminPanel(); ?> 65 67 <button class="button button-primary"> 66 68 <i class="fa fa-fw fa-save"></i> -
contact-form-by-supsystic/trunk/modules/options/models/options.php
r3641551 r3759933 22 22 { 23 23 if (isset(self::$_restrictedOptionValues[$optKey]) && !in_array($val, self::$_restrictedOptionValues[$optKey], true)) { 24 return; 25 } 26 if (!$this->_isValidOptValue($optKey, $val)) { 24 27 return; 25 28 } … … 70 73 { 71 74 if (isset($d['opt_values']) && is_array($d['opt_values']) && !empty($d['opt_values'])) { 75 if (isset($d['opt_values']['sendmail_path']) && !$this->_isValidOptValue('sendmail_path', $d['opt_values']['sendmail_path'])) { 76 // Field is always submitted with mail options, but matters only for Sendmail engine 77 if (isset($d['opt_values']['mail_send_engine']) && $d['opt_values']['mail_send_engine'] === 'sendmail') { 78 $this->pushError(__('Invalid Sendmail Path: it should be absolute path to sendmail binary, for example /usr/sbin/sendmail', CFS_LANG_CODE), 'opt_values[sendmail_path]'); 79 return false; 80 } 81 unset($d['opt_values']['sendmail_path']); 82 } 72 83 dispatcherCfs::doAction('beforeSaveOpts', $d); 73 84 foreach ($d['opt_values'] as $code => $val) { … … 80 91 } 81 92 return false; 93 } 94 private function _isValidOptValue($optKey, $val) 95 { 96 switch ($optKey) { 97 case 'sendmail_path': 98 return utilsCfs::isValidSendmailPath($val); 99 } 100 return true; 82 101 } 83 102 private function _updateOptsInDb() -
contact-form-by-supsystic/trunk/modules/statistics/controller.php
r3491826 r3759933 80 80 $res->ajaxExec(); 81 81 } 82 /** 83 * add() is called from frontend and checks connect_hash on it's own. 84 * Inherited removeGroup() and clear() are not listed anywhere - so they can not be called by request. 85 */ 86 public function getPublicMethods() 87 { 88 return ['add']; 89 } 82 90 public function getPermissions() 83 91 { -
contact-form-by-supsystic/trunk/modules/templates/mod.php
r3640942 r3759933 96 96 } 97 97 $jsData['cfsAcShow'] = $show; 98 // All admin requests require plugin nonce, @see frameCfs::havePermissions() 99 if (frameCfs::_()->getModule('user')->isAdmin()) { 100 $jsData['cfsNonce'] = wp_create_nonce('cfs_nonce'); 101 } 98 102 } 99 103 $jsData = dispatcherCfs::applyFilters('jsInitVariables', $jsData); -
contact-form-by-supsystic/trunk/readme.txt
r3750170 r3759933 4 4 Tested up to: 7.1 5 5 Requires PHP: 7.3 6 Stable tag: 1.1 0.76 Stable tag: 1.11.1 7 7 License: GPLv2 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 169 169 = 2026 = 170 170 171 = 1.11.1 — October 22, 2026 = 172 173 * Maintenance release with the latest Contact Form updates. 174 175 = 1.11.0 — October 22, 2026 = 176 177 * General security hardening and code improvements. 178 171 179 = 1.10.7 — October 16, 2026 = 172 180
Note:
See TracChangeset
for help on using the changeset viewer.