AAE-22612 Fix unwanted comma in rich text editor (#9685)

This commit is contained in:
Tomasz Gnyp
2024-05-16 16:34:57 +02:00
committed by GitHub
parent c71d8da9fe
commit 5f82106044
3 changed files with 53 additions and 22 deletions

View File

@@ -143,7 +143,8 @@
"BPMECM", "BPMECM",
"berseria", "berseria",
"zestiria", "zestiria",
"validatable" "validatable",
"edjs"
], ],
"dictionaries": [ "dictionaries": [
"html", "html",

View File

@@ -19,7 +19,6 @@ import { DebugElement } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { CoreTestingModule } from '@alfresco/adf-core'; import { CoreTestingModule } from '@alfresco/adf-core';
import { DisplayRichTextWidgetComponent } from './display-rich-text.widget'; import { DisplayRichTextWidgetComponent } from './display-rich-text.widget';
describe('DisplayRichTextWidgetComponent', () => { describe('DisplayRichTextWidgetComponent', () => {
@@ -44,28 +43,40 @@ describe('DisplayRichTextWidgetComponent', () => {
text: 'Editor.js', text: 'Editor.js',
level: 1 level: 1
} }
},
{
id: '2',
type: 'paragraph',
data: {
text: 'Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark>'
}
}
],
version: 1
}
};
const mockUnsafeFormField: any = {
id: 'fake-unsafe-form-field',
name: 'fake-label',
value: {
time: 1658154611110,
blocks: [
{
id: '1',
type: 'paragraph',
data: {
text: '<img src="x" onerror="alert(\'XSS\')">'
}
} }
], ],
version: 1 version: 1
},
required: false,
readOnly: false,
overrideId: false,
colspan: 1,
placeholder: null,
minLength: 0,
maxLength: 0,
params: {
existingColspan: 1,
maxColspan: 1
} }
}; };
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [CoreTestingModule]
CoreTestingModule
]
}); });
fixture = TestBed.createComponent(DisplayRichTextWidgetComponent); fixture = TestBed.createComponent(DisplayRichTextWidgetComponent);
widget = fixture.componentInstance; widget = fixture.componentInstance;
@@ -79,11 +90,22 @@ describe('DisplayRichTextWidgetComponent', () => {
}); });
it('should parse editorjs data to html', async () => { it('should parse editorjs data to html', async () => {
const expectedHtml = '<h1>Editor.js</h1>'; const expectedHtml = '<h1>Editor.js</h1><p>Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark></p>';
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable(); await fixture.whenStable();
const parsedHtmlEl = debugEl.query(By.css(cssSelector.parsedHTML)); const parsedHtmlEl = debugEl.query(By.css(cssSelector.parsedHTML));
expect(parsedHtmlEl.nativeElement.innerHTML).toEqual(expectedHtml); expect(parsedHtmlEl.nativeElement.innerHTML).toEqual(expectedHtml);
}); });
it('should sanitize unsafe HTML', async () => {
widget.field = mockUnsafeFormField;
fixture.detectChanges();
await fixture.whenStable();
const parsedHtmlEl = debugEl.query(By.css(cssSelector.parsedHTML));
expect(parsedHtmlEl.nativeElement.innerHTML.includes('<img src="x" onerror="alert(\'XSS\')">')).toBe(false);
});
}); });

View File

@@ -17,10 +17,11 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, SecurityContext, ViewEncapsulation } from '@angular/core';
import { WidgetComponent, FormService } from '@alfresco/adf-core'; import { WidgetComponent, FormService } from '@alfresco/adf-core';
/* cspell:disable-next-line */
import edjsHTML from 'editorjs-html'; import edjsHTML from 'editorjs-html';
import { DomSanitizer } from '@angular/platform-browser';
@Component({ @Component({
selector: 'display-rich-text', selector: 'display-rich-text',
templateUrl: './display-rich-text.widget.html', templateUrl: './display-rich-text.widget.html',
@@ -39,16 +40,23 @@ import edjsHTML from 'editorjs-html';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class DisplayRichTextWidgetComponent extends WidgetComponent implements OnInit { export class DisplayRichTextWidgetComponent extends WidgetComponent implements OnInit {
parsedHTML: any; parsedHTML: any;
constructor(public formService: FormService) { constructor(public formService: FormService, private readonly sanitizer: DomSanitizer) {
super(formService); super(formService);
} }
ngOnInit(): void { ngOnInit(): void {
/* cspell:disable-next-line */
this.parsedHTML = edjsHTML().parseStrict(this.field.value); this.parsedHTML = edjsHTML().parseStrict(this.field.value);
if (!(this.parsedHTML instanceof Error)) {
this.sanitizeHtmlContent();
} else {
throw this.parsedHTML;
}
} }
private sanitizeHtmlContent(): void {
this.parsedHTML = this.sanitizer.sanitize(SecurityContext.HTML, this.parsedHTML.join(''));
}
} }