Skip to content

Commit

Permalink
Merge pull request #252 from ghiscoding/feat/sanitizer
Browse files Browse the repository at this point in the history
feat: add `sanitizer` option to be CSP safe
  • Loading branch information
uvarov-frontend authored Jul 28, 2024
2 parents 9c94ea5 + 5fa0391 commit f3126c0
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 5 deletions.
23 changes: 23 additions & 0 deletions docs/en/reference/main/main-settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,35 @@ new VanillaCalendar('#calendar', {
```

When the option is enabled and 1 or more selected date(s) are provided but without providing `selected.month` and `selected.year`, it will make the calendar jump to the first selected date. If set to `false`, the calendar will always open to the current month and year.

<Info>
This option has no effect when `selected.month` and `selected.year` are provided.
</Info>

- - -

## sanitizer

`Type: Function`

`Default: (html) => html`

```js
import DOMPurify from 'dompurify';

new VanillaCalendar('#calendar', {
sanitizer: (html) => DOMPurify.sanitize(html),
});
```

The `sanitizer` will sanitize HTML templates to be CSP safe.

<Info>
Please note that the external library <a href="https://www.npmjs.com/package/dompurify" target="_blank" rel="nofollow noreferrer">`dompurify`</a> is used as an example. Since `sanitizer` is not required for the calendar to function, using an external library helps avoid increasing the calendar's code size.
</Info>

- - -

## date.min

`Type: String`
Expand Down
23 changes: 23 additions & 0 deletions docs/ru/reference/main/main-settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,35 @@ new VanillaCalendar('#calendar', {
```

Если эта опция включена и указаны одна или несколько выбранных дат, но без указания `selected.month` и `selected.year`, календарь перейдет к первой выбранной дате. Если установлено значение `false`, календарь всегда будет открываться для текущего месяца и года.

<Info>
Эта опция не имеет эффекта, если указаны `selected.month` и `selected.year`.
</Info>

- - -

## sanitizer

`Type: Function`

`Default: (html) => html`

```js
import DOMPurify from 'dompurify';

new VanillaCalendar('#calendar', {
sanitizer: (html) => DOMPurify.sanitize(html),
});
```

`sanitizer` будет очищать HTML-шаблоны, чтобы они были безопасными для CSP.

<Info>
Обратите внимание, что в качестве примера используется сторонняя библиотека <a href="https://www.npmjs.com/package/dompurify" target="_blank" rel="nofollow noreferrer">`dompurify`</a>. Поскольку `sanitizer` не является обязательным для работы календаря, подключение сторонней библиотеки помогает избежать увеличения кода календаря.
</Info>

- - -

## date.min

`Type: String`
Expand Down
1 change: 1 addition & 0 deletions package/src/scripts/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export default class DefaultOptionsCalendar {
months: [],
weekday: [],
};
sanitizer = (dirtyHtml: string) => dirtyHtml;
actions: T.IActions = {
clickDay: null,
clickWeekNumber: null,
Expand Down
5 changes: 3 additions & 2 deletions package/src/scripts/helpers/parseComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import getComponent from '@scripts/helpers/getComponent';
export const DOMParser = (self: VanillaCalendar, template: string) => (
template.replace(/[\n\t]/g, '').replace(/<#(?!\/?Multiple)(.*?)>/g, (_, p1) => {
const component = getComponent(p1.replace(/[/\s\n\t]/g, ''));
return component ? component(self) : '';
const html = component ? component(self) : '';
return self.sanitizer(html);
})
).replace(/[\n\t]/g, '');

Expand All @@ -14,6 +15,6 @@ export const MultipleParser = (self: VanillaCalendar, template: string) => (
for (let i = 0; i < (self.correctMonths as number); i++) {
content += p1;
}
return content;
return self.sanitizer(content);
})
).replace(/[\n\t]/g, '');
6 changes: 3 additions & 3 deletions package/src/scripts/methods/createTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import VanillaCalendar from '@src/vanilla-calendar';
import transformTime24 from '@scripts/helpers/transformTime24';
import changeTime from '@scripts/methods/changeTime';

export const InputTime = (name:string, CSSClass: string, value: string, range: boolean) => (`
export const InputTime = (name: string, CSSClass: string, value: string, range: boolean) => (`
<label class="${CSSClass}">
<input type="text"
name="${name}"
Expand Down Expand Up @@ -32,7 +32,7 @@ const createTime = (self: VanillaCalendar) => {
const [minHour, maxHour] = [0, 23];
const [minMinutes, maxMinutes] = [0, 59];

timeEl.innerHTML = (`
timeEl.innerHTML = self.sanitizer(`
<div class="${self.CSSClasses.timeContent}">
${InputTime('hours', self.CSSClasses.timeHours, self.selectedHours, range)}
${InputTime('minutes', self.CSSClasses.timeMinutes, self.selectedMinutes, range)}
Expand All @@ -42,7 +42,7 @@ const createTime = (self: VanillaCalendar) => {
</div>
<div class="${self.CSSClasses.timeRanges}">
${RangeTime('hours', self.CSSClasses.timeRange, minHour, maxHour, self.settings.selection.stepHours, self.selectedKeeping
? transformTime24(self.selectedHours, self.selectedKeeping) : self.selectedHours)}
? transformTime24(self.selectedHours, self.selectedKeeping) : self.selectedHours)}
${RangeTime('minutes', self.CSSClasses.timeRange, minMinutes, maxMinutes, self.settings.selection.stepMinutes, self.selectedMinutes)}
</div>
`);
Expand Down
1 change: 1 addition & 0 deletions package/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export interface IOptions {
jumpMonths?: number;
jumpToSelectedDate?: boolean;
date?: Partial<IDates>;
sanitizer?: (dirtyHtml: string) => unknown;
settings?: Partial<{
lang: string;
iso8601: boolean;
Expand Down

0 comments on commit f3126c0

Please sign in to comment.