diff --git a/wysiwyg_filter.admin.inc b/wysiwyg_filter.admin.inc
index 38fb424..44ca9cc 100644
--- a/wysiwyg_filter.admin.inc
+++ b/wysiwyg_filter.admin.inc
@@ -16,7 +16,7 @@
* * remove format suffix, will be first array index
* * care for pre- and post-processing, or remove it like parsed-elements
* * rewrite validate to get correct values like $form['filters']['settings'][$name] / $form_state['values']['filters'][$name]['settings']
- *
+ *
*/
function wysiwyg_filter_filter_wysiwyg_settings(&$form, &$form_state, $filter, $format, $defaults, $filters) {
global $base_url;
@@ -26,10 +26,10 @@ function wysiwyg_filter_filter_wysiwyg_settings(&$form, &$form_state, $filter, $
$settings = $filter->settings;
$settings += $defaults;
-
+
// carry over settings for other formats
$filterform = array();
-
+
// *** valid elements ***
$valid_elements = $settings['valid_elements'];
$valid_elements_rows = min(20, max(5, substr_count($valid_elements, "\n") + 2));
@@ -111,6 +111,7 @@ This option allows you to specify which HTML elements and attributes are allowed
$valid_elements_parsed = wysiwyg_filter_parse_valid_elements($settings['valid_elements']);
foreach (wysiwyg_filter_get_advanced_rules() as $rule_key => $rule_info) {
$field_name = "rule_$rule_key";
+ $field_bypass_name = "rule_bypass_$rule_key";
$default_value = wysiwyg_filter_array2csv($settings[$field_name]);
$filterform[$field_name] = array(
'#type' => 'textarea',
@@ -120,10 +121,16 @@ This option allows you to specify which HTML elements and attributes are allowed
'#rows' => min(10, max(2, substr_count($default_value, "\n") + 2)),
'#description' => $rule_info['description'],
);
+ $filterform[$field_bypass_name] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Bypass %rule', array('%rule' => $rule_info['title'])),
+ '#default_value' => !empty($settings[$field_bypass_name]),
+ '#description' => t('Bypassing this rule may lead to security vulnerabilities. Only grant this filter to trusted roles.'),
+ );
// Display warning if the field is empty but the rule definition is not
// complete.
- if (empty($default_value) && !_wysiwyg_filter_is_rule_definition_complete($rule_info, $valid_elements_parsed, $enabled_style_properties)) {
+ if (empty($settings[$field_bypass_name]) && empty($default_value) && !_wysiwyg_filter_is_rule_definition_complete($rule_info, $valid_elements_parsed, $enabled_style_properties)) {
drupal_set_message($rule_info['required_by_message'], 'warning');
}
}
@@ -163,7 +170,7 @@ This option allows you to specify which HTML elements and attributes are allowed
/*
* Implements hook_form_FORM_ID_alter
- *
+ *
* add validate and submit handlers
*/
function wysiwyg_filter_form_filter_admin_format_form_alter(&$form, &$form_state, $form_id) {
@@ -215,7 +222,9 @@ function _wysiwyg_filter_clear_messages() {
$messages = drupal_get_messages('warning');
if (!empty($messages)) {
foreach (wysiwyg_filter_get_advanced_rules() as $rule_info) {
- $my_messages[] = $rule_info['required_by_message'];
+ if (empty($settings["rule_bypass_$rule_key"])) {
+ $my_messages[] = $rule_info['required_by_message'];
+ }
}
foreach ($messages['warning'] as $warning) {
if (!in_array($warning, $my_messages)) {
@@ -248,22 +257,24 @@ function wysiwyg_filter_filter_wysiwyg_settings_validate($form, &$form_state) {
form_set_error('valid_elements', t('The following elements cannot be allowed: %elements.', array('%elements' => implode(', ', $forbidden_elements))));
}
- // *** validate nofollow_domains ***
+ // *** validate advanced rules ***
foreach (wysiwyg_filter_get_advanced_rules() as $rule_key => $rule_info) {
- $field_name = "rule_$rule_key";
- $expressions = array_filter(explode(',', preg_replace('#\s+#', ',', trim($values[$field_name])))); // form2db
- $errors = array();
- foreach ($expressions as $expression) {
- if (preg_match('`[*?]\*|\*\?`', $expression)) {
- $errors[] = t('Invalid expression %expression. Please, do not use more than one consecutive asterisk (**) or one that is next to a question mark wildcard (?* or *?).', array('%expression' => $expression));
+ if (empty($settings["rule_bypass_$rule_key"])) {
+ $field_name = "rule_$rule_key";
+ $expressions = array_filter(explode(',', preg_replace('#\s+#', ',', trim($values[$field_name])))); // form2db
+ $errors = array();
+ foreach ($expressions as $expression) {
+ if (preg_match('`[*?]\*|\*\?`', $expression)) {
+ $errors[] = t('Invalid expression %expression. Please, do not use more than one consecutive asterisk (**) or one that is next to a question mark wildcard (?* or *?).', array('%expression' => $expression));
+ }
+ if (!preg_match($rule_info['validate_regexp'], $expression)) {
+ $errors[] = t('Invalid expression %expression. Please, check the syntax of the %field field.', array('%expression' => $expression, '%field' => $rule_info['title']));
+ }
}
- if (!preg_match($rule_info['validate_regexp'], $expression)) {
- $errors[] = t('Invalid expression %expression. Please, check the syntax of the %field field.', array('%expression' => $expression, '%field' => $rule_info['title']));
+ if (!empty($errors)) {
+ form_set_error($field_name, implode('
', $errors));
}
}
- if (!empty($errors)) {
- form_set_error($field_name, implode('
', $errors));
- }
}
// *** validate nofollow_domains ***
@@ -285,10 +296,10 @@ function wysiwyg_filter_filter_wysiwyg_settings_validate($form, &$form_state) {
*/
function wysiwyg_filter_filter_wysiwyg_settings_submit($form, &$form_state) {
$values =& $form_state['values']['filters']['wysiwyg']['settings'];
-
+
// *** prepare valid_elements - just trim ***
$values['valid_elements'] = trim($values['valid_elements']);
-
+
// *** prepare rules - csv2array ***
foreach (array_keys(wysiwyg_filter_get_advanced_rules()) as $rule_key) {
$field_name = "rule_$rule_key";
@@ -301,7 +312,7 @@ function wysiwyg_filter_filter_wysiwyg_settings_submit($form, &$form_state) {
/*
* CSV to Array
- *
+ *
* @param atring $v
* @param bool $space2comma - shall we convet whitespace to commas before processing?
* @return array
@@ -312,7 +323,7 @@ function wysiwyg_filter_csv2array($v, $space2comma = TRUE) {
}
/*
* Array to CSV
- *
+ *
* @param array $v
* @return string
*/
diff --git a/wysiwyg_filter.inc b/wysiwyg_filter.inc
index 18f68c9..f10ea81 100644
--- a/wysiwyg_filter.inc
+++ b/wysiwyg_filter.inc
@@ -493,9 +493,12 @@ function wysiwyg_filter_get_filter_options($format_name, $settings) {
'nofollow_domains' => $settings['nofollow_domains'],
);
foreach (wysiwyg_filter_get_advanced_rules() as $rule_key => $rule_info) {
- $filter_options[$rule_key] = array();
- foreach ($settings["rule_$rule_key"] as $rule) {
- $filter_options[$rule_key][] = '`^' . str_replace("\xFF", $rule_info['asterisk_expansion'], preg_quote(str_replace('*', "\xFF", $rule), '`')) . '$`';
+ $filter_options["rule_bypass_$rule_key"] = !empty($settings["rule_bypass_$rule_key"]);
+ if (!$filter_options["rule_bypass_$rule_key"]) {
+ $filter_options[$rule_key] = array();
+ foreach ($settings["rule_$rule_key"] as $rule) {
+ $filter_options[$rule_key][] = '`^' . str_replace("\xFF", $rule_info['asterisk_expansion'], preg_quote(str_replace('*', "\xFF", $rule), '`')) . '$`';
+ }
}
}
return $filter_options;
diff --git a/wysiwyg_filter.module b/wysiwyg_filter.module
index 5eca4ea..1473dd4 100644
--- a/wysiwyg_filter.module
+++ b/wysiwyg_filter.module
@@ -21,7 +21,7 @@ function wysiwyg_filter_filter_info() {
$filters = array();
global $base_url;
$parts = parse_url($base_url);
-
+
$defaults = array(
'valid_elements' => wysiwyg_filter_default_valid_elements(),
'allow_comments' => 0,
@@ -33,13 +33,14 @@ function wysiwyg_filter_filter_info() {
endforeach;
foreach(wysiwyg_filter_get_advanced_rules() as $rule => $stuff):
$defaults["rule_$rule"] = array();
+ $defaults["rule_bypass_$rule"] = 0;
endforeach;
-
+
$filters['wysiwyg'] = array(
- 'title' => t('WYSIWYG Filter'),
- 'description' => t('Allows you to restrict whether users can post HTML and which tags and attributes per HTML tag to filter out.'),
- 'process callback' => 'wysiwyg_filter_filter_wysiwyg_process',
- 'settings callback' => 'wysiwyg_filter_filter_wysiwyg_settings',
+ 'title' => t('WYSIWYG Filter'),
+ 'description' => t('Allows you to restrict whether users can post HTML and which tags and attributes per HTML tag to filter out.'),
+ 'process callback' => 'wysiwyg_filter_filter_wysiwyg_process',
+ 'settings callback' => 'wysiwyg_filter_filter_wysiwyg_settings',
'tips callback' => 'wysiwyg_filter_filter_wysiwyg_tips',
'default settings' => $defaults
);
@@ -78,7 +79,7 @@ function wysiwyg_filter_wysiwyg_editor_settings_alter(&$editor_settings, $contex
// Filter is enabled in the input format related to the current given context.
if ($context['profile']->editor == 'tinymce'):
// first get the filters and their settings
- if (isset($context['profile']->format)):
+ if (isset($context['profile']->format)):
$format_name = $context['profile']->format;
$filters = filter_list_format($format_name);
if($filters && array_key_exists('wysiwyg', $filters)):
diff --git a/wysiwyg_filter.pages.inc b/wysiwyg_filter.pages.inc
index 40b5e3e..a61b47f 100644
--- a/wysiwyg_filter.pages.inc
+++ b/wysiwyg_filter.pages.inc
@@ -152,13 +152,27 @@ function _wysiwyg_filter_xss_attributes($attr, $element = '') {
$filter_options = $attr;
return;
}
-
// Shortcuts for filter options.
$allowed_attributes = &$filter_options['valid_elements'][$element];
$allowed_properties = &$filter_options['style_properties'];
- $allowed_style_urls = &$filter_options['style_urls'];
- $allowed_class_names = &$filter_options['valid_classes'];
- $allowed_element_ids = &$filter_options['valid_ids'];
+ if ($filter_options['rule_bypass_style_urls']) {
+ $allowed_style_urls = array();
+ }
+ else {
+ $allowed_style_urls = &$filter_options['style_urls'];
+ }
+ $bypass_valid_classes = $filter_options['rule_bypass_valid_classes'];
+ if (!$bypass_valid_classes) {
+ $allowed_class_names = &$filter_options['valid_classes'];
+ }
+ $bypass_valid_ids = $filter_options['rule_bypass_valid_ids'];
+ if ($bypass_valid_ids) {
+ $allowed_element_ids = array('/.*/');
+ }
+ else {
+ $allowed_element_ids = &$filter_options['valid_ids'];
+ }
+
$nofollow_policy = &$filter_options['nofollow_policy'];
$nofollow_domains = &$filter_options['nofollow_domains'];
@@ -391,13 +405,19 @@ function _wysiwyg_filter_xss_attributes($attr, $element = '') {
// sign is not allowed, there's no need here to check for bad protocols.
$dirty_names = array_filter(array_map('trim', explode(' ', decode_entities($attrinfo['value']))));
$valid_names = array();
- foreach ($dirty_names as $dirty_name) {
- foreach ($allowed_class_names as $regexp) {
- if (preg_match($regexp, $dirty_name)) {
- $valid_names[] = $dirty_name;
+ if ($bypass_valid_classes) {
+ $valid_names = $dirty_names;
+ }
+ else {
+ foreach ($dirty_names as $dirty_name) {
+ foreach ($allowed_class_names as $regexp) {
+ if (preg_match($regexp, $dirty_name)) {
+ $valid_names[] = $dirty_name;
+ }
}
}
}
+
if (empty($valid_names)) {
// Ignore attribute if no class name remains after validation.
continue;
@@ -426,6 +446,7 @@ function _wysiwyg_filter_xss_attributes($attr, $element = '') {
// Ignore attribute if it contains invalid value.
continue;
}
+
// Element ID is valid, check_plain result.
$attrinfo['value'] = check_plain($attrinfo['value']);
}