Skip to content

Commit f7de35a

Browse files
authored
Patch: Revert "Strip invisible Unicode from content model at editor initialization" (#3326)
* Revert "Strip invisible Unicode from content model at editor initialization" (#3324) * update version
1 parent 569fa29 commit f7de35a

10 files changed

Lines changed: 10 additions & 645 deletions

File tree

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
1-
import { stripInvisibleUnicode } from 'roosterjs-content-model-dom';
2-
31
/**
42
* @internal Check if there is XSS attack in the link
53
* @param link The link to be checked
6-
* @returns The safe link with invisible Unicode characters stripped, or empty string if there is XSS attack
7-
* @remarks This function strips invisible Unicode characters (zero-width chars, Unicode Tags, etc.)
8-
* and checks for patterns like s\nc\nr\ni\np\nt: to prevent XSS attacks. This may block some valid links,
4+
* @returns The safe link, or empty string if there is XSS attack
5+
* @remarks This function checks for patterns like s\nc\nr\ni\np\nt: to prevent XSS attacks. This may block some valid links,
96
* but it is necessary for security reasons. We treat the word "script" as safe if there are "/" before it.
107
*/
118
export function checkXss(link: string): string {
12-
// Defense-in-depth: strip invisible Unicode even if already handled elsewhere
13-
const sanitized = stripInvisibleUnicode(link);
14-
return sanitized.match(/^[^\/]*s\n*c\n*r\n*i\n*p\n*t\n*:/i) ? '' : sanitized;
9+
return link.match(/^[^\/]*s\n*c\n*r\n*i\n*p\n*t\n*:/i) ? '' : link;
1510
}

packages/roosterjs-content-model-api/test/publicApi/utils/checkXssTest.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,36 +30,4 @@ describe('checkXss', () => {
3030
const link = 'https://example.com/script:.js';
3131
expect(checkXss(link)).toBe(link);
3232
});
33-
34-
it('should strip invisible Unicode from link', () => {
35-
const link = 'https://www\u200B.example\u200C.com';
36-
expect(checkXss(link)).toBe('https://www.example.com');
37-
});
38-
39-
it('should strip invisible Unicode from mailto link', () => {
40-
const link = 'mailto:\u200Buser@example.com';
41-
expect(checkXss(link)).toBe('mailto:user@example.com');
42-
});
43-
44-
it('should detect XSS hidden behind invisible Unicode in script:', () => {
45-
// script: with zero-width spaces between characters should still be caught
46-
const link = 's\u200Bc\u200Cr\u200Di\u200Ep\u200Ft:alert(1)';
47-
expect(checkXss(link)).toBe('');
48-
});
49-
50-
it('should strip Unicode Tags (supplementary plane) from link', () => {
51-
// U+E0061 = \uDB40\uDC61 (Tag Latin Small Letter A)
52-
const link = 'mailto:\uDB40\uDC61user@example.com';
53-
expect(checkXss(link)).toBe('mailto:user@example.com');
54-
});
55-
56-
it('should strip bidirectional marks from link', () => {
57-
const link = 'mailto:\u202Auser\u202E@example.com';
58-
expect(checkXss(link)).toBe('mailto:user@example.com');
59-
});
60-
61-
it('should strip invisible Unicode from mailto subject and body', () => {
62-
const link = 'mailto:user@example.com?subject=Hello\u200BWorld&body=Test\u200CContent';
63-
expect(checkXss(link)).toBe('mailto:user@example.com?subject=HelloWorld&body=TestContent');
64-
});
6533
});

packages/roosterjs-content-model-core/lib/editor/Editor.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
transformColor,
77
createDomToModelContextWithConfig,
88
domToContentModel,
9-
sanitizeInvisibleUnicode,
109
} from 'roosterjs-content-model-dom';
1110
import type {
1211
ContentModelDocument,
@@ -53,8 +52,6 @@ export class Editor implements IEditor {
5352
const initialModel =
5453
options.initialModel ?? createEmptyModel(this.core.format.defaultFormat);
5554

56-
sanitizeInvisibleUnicode(initialModel);
57-
5855
this.core.api.setContentModel(
5956
this.core,
6057
initialModel,

packages/roosterjs-content-model-core/test/editor/EditorTest.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ describe('Editor', () => {
2626
updateKnownColorSpy = jasmine.createSpy('updateKnownColor');
2727
createEditorCoreSpy = spyOn(createEditorCore, 'createEditorCore').and.callThrough();
2828
setContentModelSpy = jasmine.createSpy('setContentModel');
29-
createEmptyModelSpy = spyOn(createEmptyModel, 'createEmptyModel').and.callThrough();
29+
createEmptyModelSpy = spyOn(createEmptyModel, 'createEmptyModel');
3030
});
3131

3232
it('ctor and dispose, no options', () => {
3333
const div = document.createElement('div');
3434

35+
createEmptyModelSpy.and.callThrough();
36+
3537
const editor = new Editor(div);
3638

3739
expect(createEditorCoreSpy).toHaveBeenCalledWith(div, {});
@@ -65,7 +67,7 @@ describe('Editor', () => {
6567
} as any;
6668
const setContentModelSpy = jasmine.createSpy('setContentModel');
6769
const disposeErrorHandlerSpy = jasmine.createSpy('disposeErrorHandler');
68-
const mockedInitialModel = { blocks: [] } as any;
70+
const mockedInitialModel = 'INITMODEL' as any;
6971
const options: EditorOptions = {
7072
plugins: [mockedPlugin1, mockedPlugin2],
7173
disposeErrorHandler: disposeErrorHandlerSpy,
@@ -76,6 +78,8 @@ describe('Editor', () => {
7678
},
7779
};
7880

81+
createEmptyModelSpy.and.callThrough();
82+
7983
const editor = new Editor(div, options);
8084

8185
expect(createEditorCoreSpy).toHaveBeenCalledWith(div, options);

packages/roosterjs-content-model-dom/lib/domUtils/stripInvisibleUnicode.ts

Lines changed: 0 additions & 18 deletions
This file was deleted.

packages/roosterjs-content-model-dom/lib/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ export { addTextSegment } from './modelApi/common/addTextSegment';
7070
export { normalizeParagraph } from './modelApi/common/normalizeParagraph';
7171

7272
export { normalizeContentModel } from './modelApi/common/normalizeContentModel';
73-
export { sanitizeInvisibleUnicode } from './modelApi/common/sanitizeInvisibleUnicode';
7473
export { isGeneralSegment } from './modelApi/typeCheck/isGeneralSegment';
7574
export { unwrapBlock } from './modelApi/common/unwrapBlock';
7675
export { addSegment } from './modelApi/common/addSegment';
@@ -119,7 +118,6 @@ export { isCharacterValue, isModifierKey, isCursorMovingKey } from './domUtils/e
119118
export { getNodePositionFromEvent } from './domUtils/event/getNodePositionFromEvent';
120119
export { combineBorderValue, extractBorderValues } from './domUtils/style/borderValues';
121120
export { isPunctuation, isSpace, normalizeText } from './domUtils/stringUtil';
122-
export { stripInvisibleUnicode } from './domUtils/stripInvisibleUnicode';
123121
export { parseTableCells } from './domUtils/table/parseTableCells';
124122
export { readFile } from './domUtils/readFile';
125123
export { retrieveDocumentMetadata } from './domUtils/retrieveDocumentMetadata';

packages/roosterjs-content-model-dom/lib/modelApi/common/sanitizeInvisibleUnicode.ts

Lines changed: 0 additions & 89 deletions
This file was deleted.

0 commit comments

Comments
 (0)