updated webform, webform_localization, profile2, term_merge, search_api_saved_pages, rules, redirect, overide_node_options
This commit is contained in:
@@ -50,19 +50,28 @@ the URLs).
|
||||
INSTALLATION
|
||||
============
|
||||
|
||||
- Copy all contents of this package to your modules directory preserving
|
||||
subdirectory structure.
|
||||
For module installation instructions please see:
|
||||
http://drupal.org/documentation/install/modules-themes/modules-7
|
||||
|
||||
- Goto admin/build/modules to install the module.
|
||||
|
||||
- Goto admin/settings/filters and create a new input format as follows:
|
||||
CONFIGURATION
|
||||
=============
|
||||
|
||||
- Input format name: WYSIWYG Filter (or something similar of your choice).
|
||||
- Check the filters: WYSIWYG Filter and HTML Corrector. Save.
|
||||
- Goto Rearrange tab.
|
||||
- Drag the WYSIWYG Filter on top of the HTML Corrector. Save.
|
||||
- Goto the Configure tab of your newly created WYSIWYG Filter and setup the
|
||||
available options to suit your needs.
|
||||
After installation you can configure the WYWIWYG filter:
|
||||
|
||||
1) On your site visit Admin > Configuration > Text formats (under 'Content
|
||||
authoring'): admin/config/content/formats
|
||||
|
||||
2) Add a new text format, or configure the existing text format that you would
|
||||
like to apply the WYSIWYG filter to.
|
||||
|
||||
3) Tick the 'WYSIWYG filter' option under 'Enabled filters'.
|
||||
|
||||
4) Configure the WYSIWYG filter options to suit your needs under the 'Filter
|
||||
settings' heading and save when done.
|
||||
|
||||
Note: Be aware of the 'Filter processing order'. WYSIWYG Filter should normally
|
||||
be arranged above the 'HTML Corrector' if it is being used.
|
||||
|
||||
|
||||
SECURITY ISSUES
|
||||
|
@@ -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');
|
||||
}
|
||||
}
|
||||
@@ -139,6 +146,7 @@ This option allows you to specify which HTML elements and attributes are allowed
|
||||
'#options' => array(
|
||||
'disabled' => t('Disabled - Do not add rel="nofollow" to any link.'),
|
||||
'whitelist' => t('Whitelist - Add rel="nofollow" to all links except those leading to domain names specified in the list below.'),
|
||||
'whitelist_current' => t('Whitelist - Add rel="nofollow" to all links except those leading to current domain.'),
|
||||
'blacklist' => t('Blacklist - Add rel="nofollow" to all links leading to domain names specified in the list below.'),
|
||||
),
|
||||
'#default_value' => $settings['nofollow_policy'],
|
||||
@@ -163,7 +171,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) {
|
||||
@@ -208,23 +216,6 @@ function _wysiwyg_filter_is_rule_definition_complete($rule_info, $elements, $sty
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any warning message we might have set previously.
|
||||
*/
|
||||
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'];
|
||||
}
|
||||
foreach ($messages['warning'] as $warning) {
|
||||
if (!in_array($warning, $my_messages)) {
|
||||
drupal_set_message($warning, 'warning');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate filter settings form.
|
||||
*
|
||||
@@ -252,22 +243,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('<br />', $errors));
|
||||
}
|
||||
}
|
||||
if (!empty($errors)) {
|
||||
form_set_error($field_name, implode('<br />', $errors));
|
||||
}
|
||||
}
|
||||
|
||||
// *** validate nofollow_domains ***
|
||||
@@ -289,10 +282,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";
|
||||
@@ -305,7 +298,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
|
||||
@@ -316,7 +309,7 @@ function wysiwyg_filter_csv2array($v, $space2comma = TRUE) {
|
||||
}
|
||||
/*
|
||||
* Array to CSV
|
||||
*
|
||||
*
|
||||
* @param array $v
|
||||
* @return string
|
||||
*/
|
||||
|
@@ -16,19 +16,30 @@
|
||||
*/
|
||||
function wysiwyg_filter_get_advanced_rules() {
|
||||
global $base_url, $base_path;
|
||||
// CSS identifiers: https://www.w3.org/TR/CSS2/syndata.html#value-def-identifier
|
||||
// In CSS, identifiers (including element names, classes, and IDs in
|
||||
// selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646
|
||||
// characters U+00A0 and higher, plus the hyphen (-) and the underscore (_);
|
||||
// they cannot start with a digit, two hyphens, or a hyphen followed by a
|
||||
// digit. Identifiers can also contain escaped characters and any ISO 10646
|
||||
// character as a numeric code (see next item). For instance, the identifier
|
||||
// "B&W?" may be written as "B\&W\?" or "B\26 W\3F".
|
||||
// We voluntarily do not add non-ascii characters to the rule, neither do
|
||||
// we implement the exceptions "two hyphens, or a hyphen followed by a
|
||||
// digit".
|
||||
return array(
|
||||
'valid_classes' => array(
|
||||
'title' => t('Rules for Class Names'),
|
||||
'description' => t('Enter a comma separated list of rules for <em>Class Names</em>. Whitespaces and line-breaks are ignored. <em>Class Names</em> should start with an upper or lower case letter "a to z" and can be followed by one or more upper or lower case letters "a to z", digits "0 to 9", hyphens "-" and/or underscores "_". The asterisk character "*" can be used in rules to represent any number of characters from the second position of the rule. Example: "userclass*, my-font-*" are valid rules for <em>Class Names</em>, whereas "*class" is invalid.'),
|
||||
'validate_regexp' => '`^[a-zA-Z][-_a-zA-Z0-9?*]*$`',
|
||||
'description' => t('Enter a comma separated list of rules for <em>Class Names</em>. Whitespaces and line-breaks are ignored. <em>Class Names</em> should start with an upper or lower case letter "a to z", hyphens "-" and/or underscores "_", and can be followed by one or more upper or lower case letters "a to z", digits "0 to 9", hyphens "-" and/or underscores "_". The asterisk character "*" can be used in rules to represent any number of characters from the second position of the rule. Example: "userclass*, my-font-*" are valid rules for <em>Class Names</em>, whereas "*class" is invalid.'),
|
||||
'validate_regexp' => '`^[-_a-zA-Z][-_a-zA-Z0-9?*]*$`',
|
||||
'asterisk_expansion' => '[-_a-zA-Z0-9]*',
|
||||
'required_by' => 'class',
|
||||
'required_by_message' => t('The <strong>class</strong> attribute is used in your <em>HTML elements and attributes</em> rules. You should specify the <em>Rules for Class Names</em> field in the "Advanced rules" section below. Leaving it unspecified will result in all class attributes filtered out.'),
|
||||
),
|
||||
'valid_ids' => array(
|
||||
'title' => t('Rules for Element IDs'),
|
||||
'description' => t('Enter a comma separated list of rules for <em>Element IDs</em>. Whitespaces and line-breaks are ignored. <em>Element IDs</em> should start with an upper or lower case letter "a to z" and can be followed by one or more upper or lower case letters "a to z", digits "0 to 9", hyphens "-" and/or underscores "_". The asterisk character "*" can be used in rules to represent any number of characters from the second position of the rule. Example: "foo*" is a valid rule for <em>Element IDs</em>, whereas "*bar" is invalid.'),
|
||||
'validate_regexp' => '`^[a-zA-Z][-_a-zA-Z0-9?*]*$`',
|
||||
'description' => t('Enter a comma separated list of rules for <em>Element IDs</em>. Whitespaces and line-breaks are ignored. <em>Element IDs</em> should start with an upper or lower case letter "a to z", hyphens "-" and/or underscores "_", and can be followed by one or more upper or lower case letters "a to z", digits "0 to 9", hyphens "-" and/or underscores "_". The asterisk character "*" can be used in rules to represent any number of characters from the second position of the rule. Example: "foo*" is a valid rule for <em>Element IDs</em>, whereas "*bar" is invalid.'),
|
||||
'validate_regexp' => '`^[-_a-zA-Z][-_a-zA-Z0-9?*]*$`',
|
||||
'asterisk_expansion' => '[-_a-zA-Z0-9]*',
|
||||
'required_by' => 'id',
|
||||
'required_by_message' => t('The <strong>id</strong> attribute is used in your <em>HTML elements and attributes</em> rules. You should specify the <em>Rules for Element IDs</em> field in the "Advanced rules" section below. Leaving it unspecified will result in all id attributes filtered out.'),
|
||||
@@ -123,6 +134,10 @@ function wysiwyg_filter_get_elements_blacklist() {
|
||||
* @see wysiwyg_filter_process()
|
||||
*/
|
||||
function wysiwyg_filter_parse_valid_elements($valid_elements) {
|
||||
$parsed_elements = &drupal_static(serialize($valid_elements));
|
||||
if (isset($parsed_elements)) {
|
||||
return $parsed_elements;
|
||||
}
|
||||
// Remove whitespaces and split valid elements from a comma separate list of items into an array.
|
||||
$valid_elements = array_map('drupal_strtolower', array_filter(explode(',', preg_replace('#\s+#', '', $valid_elements))));
|
||||
$parsed_elements = array();
|
||||
@@ -130,7 +145,7 @@ function wysiwyg_filter_parse_valid_elements($valid_elements) {
|
||||
foreach ($valid_elements as $valid_element) {
|
||||
// Extract the element name and its allowed attributes list
|
||||
// including special characters that will be parsed later.
|
||||
if (preg_match('`^(@|[#+-]{0,1}[a-z0-9/]+)(\[([^]]*)\])*$`', $valid_element, $matches)) {
|
||||
if (preg_match('`^(@|[#+-]{0,1}[a-z0-9-/]+)(\[([^]]*)\])*$`', $valid_element, $matches)) {
|
||||
// Element names can be specified by the special character "@" (used
|
||||
// to allow a common set of attributes for all valid HTML elements)
|
||||
// or a list of names separated by the special character "/".
|
||||
@@ -197,9 +212,9 @@ function wysiwyg_filter_parse_valid_elements($valid_elements) {
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain list of element names/synonyms (separated by /).
|
||||
// Consider synonyms as different elements with same exact attributes.
|
||||
foreach ($elements as $element) {
|
||||
// Get the element name.
|
||||
// If it has synonyms (separated by /), these are handled below.
|
||||
$element = array_shift($elements);
|
||||
if ($element == '@') {
|
||||
// These attributes should be enabled for all elements.
|
||||
foreach ($attributes as $attribute => $attribute_options) {
|
||||
@@ -236,6 +251,10 @@ function wysiwyg_filter_parse_valid_elements($valid_elements) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// For each synonym, instead of an attribute list, provide the name of the
|
||||
// element it is converted to.
|
||||
foreach ($elements as $synonym) {
|
||||
$parsed_elements[$synonym] = $element;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,6 +262,10 @@ function wysiwyg_filter_parse_valid_elements($valid_elements) {
|
||||
// Append commonly allowed attributes to each allowed element.
|
||||
if (!empty($common_attributes)) {
|
||||
foreach ($parsed_elements as $element => &$attributes) {
|
||||
// Skip synonyms.
|
||||
if (!is_array($parsed_elements[$element])) {
|
||||
continue;
|
||||
}
|
||||
// Do not append common attributes when all are allowed.
|
||||
if (isset($parsed_elements[$element]['*'])) {
|
||||
continue;
|
||||
@@ -291,10 +314,11 @@ function wysiwyg_filter_parse_valid_elements($valid_elements) {
|
||||
* @see wysiwyg_filter_settings_filter()
|
||||
*/
|
||||
function wysiwyg_filter_get_style_property_groups() {
|
||||
$regexp_integer = '[-]?[0-9]{1,3}';
|
||||
$regexp_number = '[-]?(?:[0-9]{0,3}|[0-9]{0,3}\.[0-9]{1,4})';
|
||||
$regexp_length = $regexp_number . '(?:px|pt|em|ex|in|cm|mm|pc)?';
|
||||
$regexp_percent = '[-]?[12]?[0-9]{1,2}%';
|
||||
$regexp_integer = '[-]?[0-9]+';
|
||||
$regexp_number = '[-]?(?:[0-9]+|[0-9]*\.[0-9]+)';
|
||||
// https://www.w3.org/TR/css3-values/#lengths
|
||||
$regexp_length = $regexp_number . '(?:px|pt|em|ex|in|cm|mm|pc|q|ch|rem|vw|vh|vmin|vmax)?';
|
||||
$regexp_percent = '[-]?[0-9]*[.]?[0-9]*%';
|
||||
$regexp_color = '#[a-fA-F0-9]{3}|#[a-fA-F0-9]{6}|rgb\(\s*[0-9]{0,3}%?(?:\s*,\s*[0-9]{0,3}%?){2}\s*\)|[a-zA-Z]+';
|
||||
$regexp_bgcolor = $regexp_color . '|transparent';
|
||||
$regexp_border_width = $regexp_length . '|thin|medium|thick';
|
||||
@@ -388,6 +412,7 @@ function wysiwyg_filter_get_style_property_groups() {
|
||||
'border-right-style' => '(?:' . $regexp_border_style . ')',
|
||||
'border-bottom-style' => '(?:' . $regexp_border_style . ')',
|
||||
'border-left-style' => '(?:' . $regexp_border_style . ')',
|
||||
'border-radius' => '(?:' . $regexp_length . ')',
|
||||
),
|
||||
),
|
||||
'dimension' => array(
|
||||
@@ -419,7 +444,7 @@ function wysiwyg_filter_get_style_property_groups() {
|
||||
'title' => t('Layout properties'),
|
||||
'properties' => array(
|
||||
'clear' => '(?:left|right|both|none)',
|
||||
'display' => '(?:none|inline|block|list-item|run-in|compact|marker|table-(?:(?:row|header|group|column)-group|row|column|cell|caption)|(?:inline-)?table)',
|
||||
'display' => '(?:none|inline|inline-block|block|list-item|run-in|compact|marker|table-(?:(?:row|header|group|column)-group|row|column|cell|caption)|(?:inline-)?table)',
|
||||
'float' => '(?:left|right|none)',
|
||||
'position' => '(?:static|relative|absolute|fixed)',
|
||||
'visibility' => '(?:visible|hidden|collapse)',
|
||||
@@ -464,7 +489,7 @@ function wysiwyg_filter_get_style_property_groups() {
|
||||
$groups['color']['properties']['background-repeat'] . '|' .
|
||||
$groups['color']['properties']['background-attachment'] . '|' .
|
||||
$groups['color']['properties']['background-position'] . ')';
|
||||
$groups['color']['properties']['background'] = '(?:' . $regexp . ')(?:(?:\s+' . $regexp . ')+)';
|
||||
$groups['color']['properties']['background'] = '(?:' . $regexp . ')(?:(?:\s*' . $regexp . ')+)';
|
||||
|
||||
// 'font' property.
|
||||
$regexp = '(?:' .
|
||||
@@ -473,7 +498,10 @@ function wysiwyg_filter_get_style_property_groups() {
|
||||
$groups['font']['properties']['font-weight'] . '|' .
|
||||
'(?:' . $groups['font']['properties']['font-size'] . ')(?:\s*/\s*' . $groups['dimension']['properties']['line-height'] . ')?|' .
|
||||
$groups['font']['properties']['font-family'] . ')';
|
||||
$groups['font']['properties']['font'] = '(?:' . $regexp . ')(?:(?:\s+' . $regexp . ')+)';
|
||||
$groups['font']['properties']['font'] = '(?:' . $regexp . ')(?:(?:\s*' . $regexp . ')+)';
|
||||
|
||||
// Allow other modules to alter groups
|
||||
drupal_alter('wysiwyg_filter_style_property_groups', $groups);
|
||||
|
||||
return $groups;
|
||||
}
|
||||
@@ -496,9 +524,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;
|
||||
|
@@ -9,9 +9,9 @@ files[] = wysiwyg_filter.install
|
||||
files[] = wysiwyg_filter.module
|
||||
files[] = wysiwyg_filter.pages.inc
|
||||
|
||||
; Information added by Drupal.org packaging script on 2016-02-04
|
||||
version = "7.x-1.6-rc3"
|
||||
; Information added by Drupal.org packaging script on 2017-10-24
|
||||
version = "7.x-1.6-rc9"
|
||||
core = "7.x"
|
||||
project = "wysiwyg_filter"
|
||||
datestamp = "1454601540"
|
||||
datestamp = "1508857147"
|
||||
|
||||
|
@@ -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)):
|
||||
|
@@ -50,16 +50,29 @@ function wysiwyg_filter_filter_wysiwyg_process($text, $filter, $format, $langcod
|
||||
// Named entities.
|
||||
$text = preg_replace('/&([A-Za-z][A-Za-z0-9]*;)/', '&\1', $text);
|
||||
|
||||
// Preg modifiers:
|
||||
// - x=extended (pattern with comments)
|
||||
// - s=dotall (here for multiline comments)
|
||||
// - m=multiline (so $ only matches EOF)
|
||||
// - u=unicode
|
||||
return preg_replace_callback('%
|
||||
(
|
||||
<(?=[^a-zA-Z!/]) # a lone <
|
||||
| # or
|
||||
<!--.*?--> # a comment
|
||||
| # or
|
||||
<[^>]*(>|$) # a string that starts with a <, up until the > or the end of the string
|
||||
< # a string that starts with a <
|
||||
( # ...and contains any number of
|
||||
"[^"]*" # double-quoted strings
|
||||
|
|
||||
\'[^\']*\' # single-quoted strings
|
||||
|
|
||||
[^"\'>] # any other char
|
||||
)*
|
||||
(>|$) # up until the > or the end of the string
|
||||
| # or
|
||||
> # just a >
|
||||
)%x', '_wysiwyg_filter_xss_split', $text);
|
||||
)%xsmu', '_wysiwyg_filter_xss_split', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +107,7 @@ function _wysiwyg_filter_xss_split($m, $store = FALSE) {
|
||||
return '<';
|
||||
}
|
||||
|
||||
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
||||
if (!preg_match('%^<\s*(/\s*)?([a-zA-Z0-9-/]+)([^>]*)>?|(<!--.*?-->)$%', $string, $matches)) {
|
||||
// Seriously malformed
|
||||
return '';
|
||||
}
|
||||
@@ -104,6 +117,11 @@ function _wysiwyg_filter_xss_split($m, $store = FALSE) {
|
||||
$attrlist = &$matches[3];
|
||||
$comment = &$matches[4];
|
||||
|
||||
// Convert synonyms to the element they get converted to.
|
||||
if (!empty($filter_options['valid_elements'][$elem]) && is_string($filter_options['valid_elements'][$elem])) {
|
||||
$elem = $filter_options['valid_elements'][$elem];
|
||||
}
|
||||
|
||||
if (!empty($comment)) {
|
||||
// Allow or disallow HTML comments.
|
||||
return (!empty($filter_options['allow_comments']) ? $comment : '');
|
||||
@@ -152,13 +170,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'];
|
||||
|
||||
@@ -263,13 +295,14 @@ function _wysiwyg_filter_xss_attributes($attr, $element = '') {
|
||||
}
|
||||
|
||||
// The attribute list ends with a valueless attribute like "selected".
|
||||
if ($mode == 1 && !$skip) {
|
||||
// is_array() ensures this isn't run for synonyms.
|
||||
if ($mode == 1 && !$skip && is_array($attrarr[$attrname])) {
|
||||
$attrarr[$attrname] = array();
|
||||
}
|
||||
|
||||
// Check the current HTML element for required attributes.
|
||||
foreach ($allowed_attributes as $attrname => $attrinfo) {
|
||||
if (!empty($attrinfo['required']) && !isset($attrarr[$attrname])) {
|
||||
if (!empty($attrinfo['required']) && empty($attrarr[$attrname]['value'])) {
|
||||
// Ignore the whole element if required attribute is not present.
|
||||
return FALSE;
|
||||
}
|
||||
@@ -391,13 +424,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 +465,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']);
|
||||
}
|
||||
@@ -440,6 +480,11 @@ function _wysiwyg_filter_xss_attributes($attr, $element = '') {
|
||||
// If this is <a href> element, then check domain name for rel="nofollow" policies in effect.
|
||||
if ($element == 'a' && $attrname == 'href' && $nofollow_policy != 'disabled' && !$add_nofollow) {
|
||||
$domain_found = FALSE;
|
||||
if ($nofollow_policy == 'whitelist_current') {
|
||||
global $base_url;
|
||||
$parts = parse_url($base_url);
|
||||
$nofollow_domains = array($parts['host']);
|
||||
}
|
||||
foreach ($nofollow_domains as $domain) {
|
||||
$domain = str_replace('.', '\.', $domain); // escape dots
|
||||
if (preg_match('#://.*' . $domain . '([^a-z0-9]|$)#i', $attrinfo['value'])) {
|
||||
@@ -447,7 +492,8 @@ function _wysiwyg_filter_xss_attributes($attr, $element = '') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (($nofollow_policy == 'blacklist' && $domain_found) || ($nofollow_policy == 'whitelist' && !$domain_found)) {
|
||||
$link_is_relative = !parse_url($attrinfo['value'], PHP_URL_HOST);
|
||||
if (($nofollow_policy == 'blacklist' && $domain_found) || (($nofollow_policy == 'whitelist' || $nofollow_policy == 'whitelist_current') && !$domain_found && !$link_is_relative)) {
|
||||
$add_nofollow = TRUE;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user