@progress/kendo-angular-editor 25.3.0-develop.1 → 25.3.0-develop.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@ import * as i1$2 from '@progress/kendo-angular-toolbar';
12
12
  import { ToolBarToolComponent, ToolBarComponent, ToolBarButtonGroupComponent, ToolBarButtonComponent, KENDO_TOOLBAR } from '@progress/kendo-angular-toolbar';
13
13
  import * as i1$1 from '@progress/kendo-angular-dialog';
14
14
  import { DialogContentBase, DialogTitleBarComponent, DialogActionsComponent, DialogContainerService, DialogService, WindowService, WindowContainerService } from '@progress/kendo-angular-dialog';
15
- import { isDocumentAvailable, guid, getLicenseMessage, shouldShowValidationUI, Keys, hasObservers, WatermarkOverlayComponent, KendoInput, KENDO_WEBMCP_HOST, provideComponentName, isPresent as isPresent$1, ResizeBatchService } from '@progress/kendo-angular-common';
15
+ import { isSafeUrl, isSafeImageUrl, isDocumentAvailable, guid, getLicenseMessage, shouldShowValidationUI, Keys, hasObservers, WatermarkOverlayComponent, KendoInput, KENDO_WEBMCP_HOST, provideComponentName, isPresent as isPresent$1, ResizeBatchService } from '@progress/kendo-angular-common';
16
16
  import { marks as marks$1, nodes as nodes$1, Schema, createTable, insertNode, alignBlocks, alignRemoveRules, canIndentAsListItem, indent, canBeIndented, indentBlocks, hasNode, liftBlockquote, canOutdentAsListItem, outdent, selectAll, expandToWordWrap, applyInlineStyle, removeLink, link, toggleInlineFormat, underline, superscript, subscript, strikethrough, italic, insertText, applyLink, cleanFormatting, bold, blockquote, undo, setHtml, redo, toggleUnorderedList, toggleOrderedList, insertImage, getHtml, formatBlockElements, isAligned, alignRightRules, alignLeftRules, alignJustifyRules, alignCenterRules, deleteTable, splitCell, mergeCells, deleteColumn, deleteRow, addRowAfter, addRowBefore, addColumnAfter, addColumnBefore, expandSelection, hasMark, getActiveMarks, isIndented, activeNode, getSelectionText as getSelectionText$1, getNodeFromSelection, getMark, removeComments, sanitize, removeAttribute, sanitizeClassAttr, sanitizeStyleAttr, TextSelection, parseContent, Plugin, PluginKey, history, keymap, buildListKeymap, buildKeymap, baseKeymap, gapCursor, imageResizing, tableResizing, tableEditing, caretColor, cspFix, placeholder, EditorState, EditorView, pasteCleanup, replaceImageSourcesFromRtf, AllSelection } from '@progress/kendo-editor-common';
17
17
  export { AllSelection, CellSelection, Decoration, DecorationSet, EditorState, EditorView, InputRule, Mark, MarkType, Node, NodeSelection, NodeType, Plugin, PluginKey, Schema, TextSelection, Transaction, baseKeymap, dropCursor, flattenNestedSpans, gapCursor, history, inputRules, keymap, tableNodes, textblockTypeInputRule, wrappingInputRule } from '@progress/kendo-editor-common';
18
18
  import { validatePackage } from '@progress/kendo-licensing';
@@ -36,8 +36,8 @@ const packageMetadata = {
36
36
  productName: 'Kendo UI for Angular',
37
37
  productCode: 'KENDOUIANGULAR',
38
38
  productCodes: ['KENDOUIANGULAR'],
39
- publishDate: 1790689508,
40
- version: '25.3.0-develop.1',
39
+ publishDate: 1790761643,
40
+ version: '25.3.0-develop.2',
41
41
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
42
42
  };
43
43
 
@@ -234,6 +234,18 @@ const insertTable = (attrs) => (state, dispatch) => {
234
234
  };
235
235
 
236
236
  const alignRemove = (state, dispatch) => alignBlocks(alignRemoveRules)(state, dispatch);
237
+ const sanitizeLinkAttrs = (attrs) => {
238
+ if (attrs && typeof attrs === 'object' && attrs.href !== undefined && !isSafeUrl(attrs.href)) {
239
+ return { ...attrs, href: '' };
240
+ }
241
+ return attrs;
242
+ };
243
+ const sanitizeImageAttrs = (attrs) => {
244
+ if (attrs && typeof attrs === 'object' && attrs.src !== undefined && !isSafeImageUrl(attrs.src)) {
245
+ return { ...attrs, src: '' };
246
+ }
247
+ return attrs;
248
+ };
237
249
  const customIndent = (state, dispatch) => {
238
250
  const listItem = state.schema.nodes[indentRules.listsTypes.listItem];
239
251
  if (canIndentAsListItem(state, listItem)) {
@@ -258,10 +270,10 @@ const customOutdent = (state, dispatch) => {
258
270
  const inlineCommand = {
259
271
  bold: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...bold, applyToWord }),
260
272
  cleanFormatting: (options) => cleanFormatting(options),
261
- createLink: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: attrs.value, applyToWord: attrs.applyToWord }),
273
+ createLink: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: sanitizeLinkAttrs(attrs.value), applyToWord: attrs.applyToWord }),
262
274
  fontFamily: attrs => expandToWordWrap(applyInlineStyle, { style: 'font-family', value: attrs.value, applyToWord: attrs.applyToWord }),
263
275
  fontSize: attrs => expandToWordWrap(applyInlineStyle, { style: 'font-size', value: attrs.value, applyToWord: attrs.applyToWord }),
264
- insertFile: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: attrs, applyToWord: attrs.applyToWord }),
276
+ insertFile: attrs => expandToWordWrap(applyLink, { mark: 'link', attrs: sanitizeLinkAttrs(attrs), applyToWord: attrs.applyToWord }),
265
277
  insertText: text => insertText(text),
266
278
  italic: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...italic, applyToWord }),
267
279
  strikethrough: (applyToWord) => expandToWordWrap(toggleInlineFormat, { ...strikethrough, applyToWord }),
@@ -281,7 +293,7 @@ const blockCommand = {
281
293
  format: formatAttr => formatBlockElements(formatAttr.tag),
282
294
  getHTML: () => getHtml,
283
295
  indent: () => customIndent,
284
- insertImage: attrs => insertImage(attrs),
296
+ insertImage: attrs => insertImage(sanitizeImageAttrs(attrs)),
285
297
  // think about changing the command name.
286
298
  insertOrderedList: () => toggleOrderedList,
287
299
  // think about changing the command name.
@@ -708,6 +720,29 @@ const replaceMessagePlaceholder = (message, replacements) => {
708
720
  replacements.forEach((replacement) => message = message.replace(new RegExp(`\\[\\[\\s*${replacement.placeholder}\\s*]]|{\\s*${replacement.placeholder}\\s*}`, 'g'), replacement.value));
709
721
  return message;
710
722
  };
723
+ /**
724
+ * @hidden
725
+ * Removes `href` and `src` attributes that use unsafe URL schemes (e.g. `javascript:`) from an HTML string.
726
+ * Uses `<template>` for inert parsing so element event handlers do not fire during sanitization.
727
+ */
728
+ const sanitizeUnsafeUrls = (html) => {
729
+ if (!html || !isDocumentAvailable()) {
730
+ return html;
731
+ }
732
+ const template = document.createElement('template');
733
+ template.innerHTML = html;
734
+ template.content.querySelectorAll('a[href]').forEach(el => {
735
+ if (!isSafeUrl(el.getAttribute('href'))) {
736
+ el.removeAttribute('href');
737
+ }
738
+ });
739
+ template.content.querySelectorAll('img[src], source[src]').forEach(el => {
740
+ if (!isSafeImageUrl(el.getAttribute('src'))) {
741
+ el.removeAttribute('src');
742
+ }
743
+ });
744
+ return template.innerHTML;
745
+ };
711
746
 
712
747
  /**
713
748
  * @hidden
@@ -834,6 +869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
834
869
  args: ['textarea', { static: true }]
835
870
  }] } });
836
871
 
872
+ const safeImageUrlValidator = (control) => isSafeImageUrl(control.value) ? null : { unsafeUrl: true };
837
873
  /**
838
874
  * @hidden
839
875
  */
@@ -842,7 +878,7 @@ class ImageDialogComponent extends DialogContentBase {
842
878
  localization;
843
879
  editor;
844
880
  srcInput;
845
- src = new FormControl('', Validators.required);
881
+ src = new FormControl('', [Validators.required, safeImageUrlValidator]);
846
882
  alt = new FormControl('');
847
883
  width = new FormControl('', Validators.min(1));
848
884
  height = new FormControl('', Validators.min(1));
@@ -1047,6 +1083,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
1047
1083
  args: ['srcInput']
1048
1084
  }] } });
1049
1085
 
1086
+ const safeUrlValidator = (control) => isSafeUrl(control.value) ? null : { unsafeUrl: true };
1050
1087
  /**
1051
1088
  * @hidden
1052
1089
  */
@@ -1057,7 +1094,7 @@ class FileLinkDialogComponent extends DialogContentBase {
1057
1094
  command;
1058
1095
  hrefInput;
1059
1096
  linkForm = new FormGroup({
1060
- 'href': new FormControl('', Validators.required),
1097
+ 'href': new FormControl('', [Validators.required, safeUrlValidator]),
1061
1098
  'text': new FormControl({ value: '', disabled: true }, Validators.required),
1062
1099
  'title': new FormControl('')
1063
1100
  });
@@ -3257,13 +3294,28 @@ const defaultPasteCleanupSettings = {
3257
3294
  };
3258
3295
  const removeCommentsIf = conditionallyExecute(removeComments);
3259
3296
  const removeInvalidHTMLIf = conditionallyExecute(sanitize);
3297
+ const sanitizeHrefAttr = (attr) => {
3298
+ if (!isSafeUrl(attr.value)) {
3299
+ removeAttribute(attr);
3300
+ }
3301
+ };
3302
+ const sanitizeSrcAttr = (attr) => {
3303
+ const owner = attr.ownerElement;
3304
+ const tag = owner ? owner.tagName : '';
3305
+ const check = (tag === 'IMG' || tag === 'SOURCE') ? isSafeImageUrl : isSafeUrl;
3306
+ if (!check(attr.value)) {
3307
+ removeAttribute(attr);
3308
+ }
3309
+ };
3260
3310
  const getPasteCleanupAttributes = (config) => {
3261
3311
  if (config.removeAttributes === 'all') {
3262
3312
  return { '*': removeAttribute };
3263
3313
  }
3264
3314
  const initial = removeEmptyEntries({
3265
3315
  style: config.removeMsStyles ? sanitizeStyleAttr : undefined,
3266
- class: config.removeMsClasses ? sanitizeClassAttr : undefined
3316
+ class: config.removeMsClasses ? sanitizeClassAttr : undefined,
3317
+ href: sanitizeHrefAttr,
3318
+ src: sanitizeSrcAttr
3267
3319
  });
3268
3320
  return config.removeAttributes.reduce((acc, curr) => ({ ...acc, [curr]: removeAttribute }), initial);
3269
3321
  };
@@ -3794,7 +3846,7 @@ class EditorComponent {
3794
3846
  }
3795
3847
  const currentSchema = this.schema || schema;
3796
3848
  const containerNativeElement = this.container.element.nativeElement;
3797
- const contentNode = parseContent((this.value || '').trim(), currentSchema, { preserveWhitespace: this.preserveWhitespace });
3849
+ const contentNode = parseContent(sanitizeUnsafeUrls((this.value || '').trim()), currentSchema, { preserveWhitespace: this.preserveWhitespace });
3798
3850
  if (this.iframe) {
3799
3851
  const iframeDoc = containerNativeElement.contentDocument;
3800
3852
  const meta = iframeDoc.createElement('meta');
@@ -4005,7 +4057,7 @@ class EditorComponent {
4005
4057
  return;
4006
4058
  }
4007
4059
  const state = this.view.state;
4008
- const nextDoc = parseContent(value || '', state.schema, { preserveWhitespace: this.preserveWhitespace });
4060
+ const nextDoc = parseContent(sanitizeUnsafeUrls(value || ''), state.schema, { preserveWhitespace: this.preserveWhitespace });
4009
4061
  const tr = state.tr
4010
4062
  .setSelection(new AllSelection(state.doc))
4011
4063
  .replaceSelectionWith(nextDoc);
@@ -7,7 +7,7 @@ export const packageMetadata = {
7
7
  "productCodes": [
8
8
  "KENDOUIANGULAR"
9
9
  ],
10
- "publishDate": 1790689508,
11
- "version": "25.3.0-develop.1",
10
+ "publishDate": 1790761643,
11
+ "version": "25.3.0-develop.2",
12
12
  "licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/"
13
13
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@progress/kendo-angular-editor",
3
- "version": "25.3.0-develop.1",
3
+ "version": "25.3.0-develop.2",
4
4
  "description": "Kendo UI Editor for Angular",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Progress",
@@ -17,7 +17,7 @@
17
17
  "package": {
18
18
  "productName": "Kendo UI for Angular",
19
19
  "productCode": "KENDOUIANGULAR",
20
- "publishDate": 1790689508,
20
+ "publishDate": 1790761643,
21
21
  "licensingDocsUrl": "https://www.telerik.com/kendo-angular-ui/my-license/"
22
22
  }
23
23
  },
@@ -29,23 +29,23 @@
29
29
  "@angular/platform-browser": "20 - 22",
30
30
  "@progress/kendo-drawing": "^1.25.0",
31
31
  "@progress/kendo-licensing": "^1.11.0",
32
- "@progress/kendo-angular-buttons": "25.3.0-develop.1",
33
- "@progress/kendo-angular-common": "25.3.0-develop.1",
34
- "@progress/kendo-angular-dialog": "25.3.0-develop.1",
35
- "@progress/kendo-angular-dropdowns": "25.3.0-develop.1",
36
- "@progress/kendo-angular-inputs": "25.3.0-develop.1",
37
- "@progress/kendo-angular-intl": "25.3.0-develop.1",
38
- "@progress/kendo-angular-l10n": "25.3.0-develop.1",
39
- "@progress/kendo-angular-label": "25.3.0-develop.1",
40
- "@progress/kendo-angular-layout": "25.3.0-develop.1",
41
- "@progress/kendo-angular-icons": "25.3.0-develop.1",
42
- "@progress/kendo-angular-popup": "25.3.0-develop.1",
43
- "@progress/kendo-angular-toolbar": "25.3.0-develop.1",
32
+ "@progress/kendo-angular-buttons": "25.3.0-develop.2",
33
+ "@progress/kendo-angular-common": "25.3.0-develop.2",
34
+ "@progress/kendo-angular-dialog": "25.3.0-develop.2",
35
+ "@progress/kendo-angular-dropdowns": "25.3.0-develop.2",
36
+ "@progress/kendo-angular-inputs": "25.3.0-develop.2",
37
+ "@progress/kendo-angular-intl": "25.3.0-develop.2",
38
+ "@progress/kendo-angular-l10n": "25.3.0-develop.2",
39
+ "@progress/kendo-angular-label": "25.3.0-develop.2",
40
+ "@progress/kendo-angular-layout": "25.3.0-develop.2",
41
+ "@progress/kendo-angular-icons": "25.3.0-develop.2",
42
+ "@progress/kendo-angular-popup": "25.3.0-develop.2",
43
+ "@progress/kendo-angular-toolbar": "25.3.0-develop.2",
44
44
  "rxjs": "^6.5.3 || ^7.0.0"
45
45
  },
46
46
  "dependencies": {
47
47
  "tslib": "^2.3.1",
48
- "@progress/kendo-angular-schematics": "25.3.0-develop.1",
48
+ "@progress/kendo-angular-schematics": "25.3.0-develop.2",
49
49
  "@progress/kendo-editor-common": "1.12.8"
50
50
  },
51
51
  "schematics": "./schematics/collection.json",
@@ -9,12 +9,12 @@ const schematics_1 = require("@angular-devkit/schematics");
9
9
  function default_1(options) {
10
10
  const finalOptions = Object.assign(Object.assign({}, options), { mainNgModule: 'EditorModule', package: 'editor', peerDependencies: {
11
11
  // peer dependencies of kendo-angular-dropdowns
12
- '@progress/kendo-angular-navigation': '25.3.0-develop.1',
13
- '@progress/kendo-angular-treeview': '25.3.0-develop.1',
12
+ '@progress/kendo-angular-navigation': '25.3.0-develop.2',
13
+ '@progress/kendo-angular-treeview': '25.3.0-develop.2',
14
14
  // peer dependency of kendo-angular-layout
15
- '@progress/kendo-angular-progressbar': '25.3.0-develop.1',
15
+ '@progress/kendo-angular-progressbar': '25.3.0-develop.2',
16
16
  // peer dependency of kendo-angular-inputs
17
- '@progress/kendo-angular-dialog': '25.3.0-develop.1',
17
+ '@progress/kendo-angular-dialog': '25.3.0-develop.2',
18
18
  // Peer dependency of icons
19
19
  '@progress/kendo-svg-icons': '^4.0.0'
20
20
  } });