diff --git a/source/changelog.txt b/source/changelog.txt
index 4e52f4a..6125179 100644
--- a/source/changelog.txt
+++ b/source/changelog.txt
@@ -9,6 +9,7 @@
#### Removed
#### Fixed
#### Security
+- Escape translated strings to prevent HTML injections
### [1.4.0]
#### Changed
diff --git a/source/front/blocks/events-list/edit.js b/source/front/blocks/events-list/edit.js
index e1c28e9..d46b5ae 100644
--- a/source/front/blocks/events-list/edit.js
+++ b/source/front/blocks/events-list/edit.js
@@ -7,6 +7,7 @@ import {
hideErrorMessages,
showLoadingIndicator,
} from '../../events-displayer.js'
+import Formatter from '../../formatter.js'
const { InspectorControls, useBlockProps } = wp.blockEditor
const { Panel, PanelBody } = wp.components
@@ -73,12 +74,18 @@ export default ({ attributes, setAttributes }) => {
return [
- ')}>
+ '),
+ )}
+ >
{
className="components-base-control__label"
htmlFor={NAME + '_group-name'}
>
- {__('Group name (optional)', '')}
+ {Formatter.escapeHTML(
+ __('Group name (optional)', ''),
+ )}
{
,
- {__('The events could not be loaded!', '')}
+ {Formatter.escapeHTML(
+ __('The events could not be loaded!', ''),
+ )}
- {__('The group could not be found!', '')}
+ {Formatter.escapeHTML(
+ __('The group could not be found!', ''),
+ )}
- {__('Loading...', '')}
+ {Formatter.escapeHTML(__('Loading...', ''))}
{
target="_blank"
style={{ display: 'inline-block', 'margin-top': '20px;' }}
>
- {__('Show more events', '')}
+ {Formatter.escapeHTML(__('Show more events', ''))}
,
]
diff --git a/source/front/formatter-test.js b/source/front/formatter-test.js
index d34dd60..b810343 100644
--- a/source/front/formatter-test.js
+++ b/source/front/formatter-test.js
@@ -1,6 +1,18 @@
import test from 'ava'
+import { JSDOM } from 'jsdom'
+
import Formatter from './formatter.js'
+test.beforeEach(() => {
+ const dom = new JSDOM()
+ global.document = dom.window.document
+})
+
+test('#escapeHTML', (t) => {
+ const escaped = Formatter.escapeHTML('a')
+ t.is(escaped, '<b>a</b>')
+})
+
test('#formatDate one date', (t) => {
const date = Formatter.formatDate({
start: '2021-04-15T10:30:00Z',
diff --git a/source/front/formatter.js b/source/front/formatter.js
index 614db12..5deda7c 100644
--- a/source/front/formatter.js
+++ b/source/front/formatter.js
@@ -1,6 +1,12 @@
import DateTimeWrapper from './date-time-wrapper.js'
export default class Formatter {
+ static escapeHTML(input) {
+ const div = document.createElement('div')
+ div.appendChild(document.createTextNode(input))
+ return div.innerHTML
+ }
+
static formatDate({ locale, timeZone, start, end, isShortOffsetNameShown }) {
const startDateTime = new DateTimeWrapper({
locale,
diff --git a/source/includes/EventsListBlock.php b/source/includes/EventsListBlock.php
index 3bdd25b..b376fa4 100644
--- a/source/includes/EventsListBlock.php
+++ b/source/includes/EventsListBlock.php
@@ -13,8 +13,8 @@ class EventsListBlock {
], '', array('in_footer' => true));
register_block_type(NAME . '/events-list', [
'api_version' => 2,
- 'title' => __('Events List', 'connector-mobilizon'),
- 'description' => __('A list of the upcoming events of the connected Mobilizon instance.', 'connector-mobilizon'),
+ 'title' => esc_html__('Events List', 'connector-mobilizon'),
+ 'description' => esc_html__('A list of the upcoming events of the connected Mobilizon instance.', 'connector-mobilizon'),
'category' => 'widgets',
'icon' => 'list-view',
'supports' => [
diff --git a/source/includes/EventsListWidget.php b/source/includes/EventsListWidget.php
index 0726a7b..bfe0a62 100644
--- a/source/includes/EventsListWidget.php
+++ b/source/includes/EventsListWidget.php
@@ -6,9 +6,9 @@ class EventsListWidget extends \WP_Widget {
public function __construct() {
parent::__construct(
NAME . '-events-list',
- NICE_NAME . ' ' . __('Events List', 'connector-mobilizon'),
+ NICE_NAME . ' ' . esc_html__('Events List', 'connector-mobilizon'),
array(
- 'description' => __('A list of the upcoming events of the connected Mobilizon instance.', 'connector-mobilizon'),
+ 'description' => esc_html__('A list of the upcoming events of the connected Mobilizon instance.', 'connector-mobilizon'),
),
);
}
@@ -49,7 +49,7 @@ class EventsListWidget extends \WP_Widget {
}
public function form($options) {
- $title = !empty($options['title']) ? $options['title'] : __('Events', 'connector-mobilizon');
+ $title = !empty($options['title']) ? $options['title'] : esc_html__('Events', 'connector-mobilizon');
$eventsCount = !empty($options['eventsCount']) ? $options['eventsCount'] : DEFAULT_EVENTS_COUNT;
$groupName = !empty($options['groupName']) ? $options['groupName'] : '';
diff --git a/source/includes/Settings.php b/source/includes/Settings.php
index 9b5feac..de33123 100644
--- a/source/includes/Settings.php
+++ b/source/includes/Settings.php
@@ -31,14 +31,14 @@ class Settings {
add_settings_section(
self::$SETTINGS_SECTION_NAME,
- __('General Settings', 'connector-mobilizon'),
+ esc_html__('General Settings', 'connector-mobilizon'),
'',
self::$PAGE_NAME
);
add_settings_field(
self::$SETTING_FIELD_NAME_URL,
- __('URL', 'connector-mobilizon'),
+ esc_html__('URL', 'connector-mobilizon'),
'MobilizonConnector\Settings::output_field_url',
self::$PAGE_NAME,
self::$SETTINGS_SECTION_NAME,
@@ -48,7 +48,7 @@ class Settings {
);
add_settings_field(
self::$SETTING_FIELD_NAME_IS_SHORT_OFFSET_NAME_SHOWN,
- __('Display named offset', 'connector-mobilizon'),
+ esc_html__('Display named offset', 'connector-mobilizon'),
'MobilizonConnector\Settings::output_field_is_short_offset_name_shown',
self::$PAGE_NAME,
self::$SETTINGS_SECTION_NAME,
@@ -74,7 +74,7 @@ class Settings {
add_settings_error(
self::$OPTION_NAME_URL,
'wordpress_mobilizon_field_url_error',
- __('The URL is invalid.', 'connector-mobilizon'),
+ esc_html__('The URL is invalid.', 'connector-mobilizon'),
'error'
);
}
@@ -86,7 +86,7 @@ class Settings {
public static function register_settings_page() {
add_options_page(
- NICE_NAME . ' ' . __('Settings', 'connector-mobilizon'),
+ NICE_NAME . ' ' . esc_html__('Settings', 'connector-mobilizon'),
NICE_NAME,
'manage_options',
NAME . '-settings',