CKEditor Config - Validate input before saving config file
authorColeman Watts <coleman@civicrm.org>
Thu, 28 May 2020 19:15:26 +0000 (15:15 -0400)
committerSeamus Lee <seamuslee001@gmail.com>
Wed, 19 Aug 2020 06:16:45 +0000 (16:16 +1000)
Also removes support for 'customConfig' supplimental file.

CRM/Admin/Form/CKEditorConfig.php
js/wysiwyg/admin.ckeditor-configurator.js

index 92180dbb4ccc678d6cd625bec09135593e3a4be6..fd1e5c8ba93e7f3331707b79661ac33d9a6f8b1b 100644 (file)
@@ -33,6 +33,7 @@ class CRM_Admin_Form_CKEditorConfig extends CRM_Core_Form {
     'extraPlugins',
     'toolbarGroups',
     'removeButtons',
+    'customConfig',
     'filebrowserBrowseUrl',
     'filebrowserImageBrowseUrl',
     'filebrowserFlashBrowseUrl',
@@ -105,23 +106,31 @@ class CRM_Admin_Form_CKEditorConfig extends CRM_Core_Form {
       // Standardize line-endings
       . preg_replace('~\R~u', "\n", $params['config']);
 
-    // Use all params starting with config_
+    // Generate a whitelist of allowed config params
+    $allOptions = json_decode(file_get_contents(\Civi::paths()->getPath('[civicrm.root]/js/wysiwyg/ck-options.json')), TRUE);
+    // These two aren't really blacklisted they're just in a different part of the form
+    $blackList = array_diff($this->blackList, ['skin', 'extraPlugins']);
+    // All options minus blacklist = whitelist
+    $whiteList = array_diff(array_column($allOptions, 'id'), $blackList);
+
+    // Save whitelisted params starting with config_
     foreach ($params as $key => $val) {
       $val = trim($val);
-      if (strpos($key, 'config_') === 0 && strlen($val)) {
+      if (strpos($key, 'config_') === 0 && strlen($val) && in_array(substr($key, 7), $whiteList)) {
         if ($val != 'true' && $val != 'false' && $val != 'null' && $val[0] != '{' && $val[0] != '[' && !is_numeric($val)) {
-          $val = json_encode($val, JSON_UNESCAPED_SLASHES);
+          $val = '"' . $val . '"';
         }
-        elseif ($val[0] == '{' || $val[0] == '[') {
-          if (!is_array(json_decode($val, TRUE))) {
-            // Invalid JSON. Do not save.
-            continue;
+        try {
+          $val = CRM_Utils_JS::encode(CRM_Utils_JS::decode($val, TRUE));
+          $pos = strrpos($config, '};');
+          $key = preg_replace('/^config_/', 'config.', $key);
+          $setting = "\n\t{$key} = {$val};\n";
+          $config = substr_replace($config, $setting, $pos, 0);
+        } catch (CRM_Core_Exception $e) {
+          if (!empty($params['save'])) {
+            CRM_Core_Session::setStatus(ts("Error saving %1.", [1 => $key]), ts('Invalid Value'), 'error');
           }
         }
-        $pos = strrpos($config, '};');
-        $key = preg_replace('/^config_/', 'config.', $key);
-        $setting = "\n\t{$key} = {$val};\n";
-        $config = substr_replace($config, $setting, $pos, 0);
       }
     }
     self::saveConfigFile($this->preset, $config);
index 00d1372e6a112ac4334451c076bc8f5dfdeb5e35..f46c48fce9b0e22a53792ce40a3d1295a7749569 100644 (file)
   }
 
   function validateJson() {
-    var val = $(this).val();
-    $(this).parent().removeClass('crm-error');
-    if (val[0] === '[' || val[0] === '{') {
-      try {
-        JSON.parse(val);
-      } catch (e) {
-        $(this).parent().addClass('crm-error');
-      }
-    }
+    // TODO: strict json isn't required so we can't use JSON.parse for error checking. Need something like angular.eval.
   }
 
   function addOption() {