Skip to content

Commit 17eac64

Browse files
committed
Decode template contents using DOMParser to ensure that HTML elements are properly decoded from Django's marksafe method.
1 parent b8b3139 commit 17eac64

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
const domParser = new DOMParser();
2+
3+
/*
4+
* JSON data that we read from Django have been passed through
5+
* Django's marksafe function that escapes any HTML characters.
6+
* Use the DOMParser to decode these before we read parse the JSON.
7+
*/
8+
function decodeMarkedSafeText(text) {
9+
const dom = domParser.parseFromString(text, 'text/html');
10+
return dom.documentElement.textContent;
11+
}
12+
113
const template = document.querySelector(`template[data-plugin="${__kolibriModuleName}"]`);
214

3-
const data = template ? JSON.parse(template.innerHTML.trim()) : {};
15+
const data = template ? JSON.parse(decodeMarkedSafeText(template.innerHTML.trim())) : {};
416

517
export default data;

packages/kolibri/internal/__tests__/pluginMediator.spec.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ describe('Mediator', function () {
415415
const moduleName = 'test';
416416
const messageMap = {
417417
test: 'test message',
418+
ampersandMessage: 'test & message',
418419
};
419420
let spy;
420421
beforeEach(function () {
@@ -432,7 +433,10 @@ describe('Mediator', function () {
432433
});
433434
it('should call Vue.registerMessages with arguments currentLanguage and messageMap', function () {
434435
mediator.registerLanguageAssets(moduleName);
435-
expect(spy).toHaveBeenCalledWith(currentLanguage, messageMap);
436+
expect(spy).toHaveBeenCalledWith(currentLanguage, {
437+
test: 'test message',
438+
ampersandMessage: 'test & message',
439+
});
436440
});
437441
});
438442
});

packages/kolibri/internal/pluginMediator.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ function mergeMixin(component) {
3535
return component;
3636
}
3737

38+
const domParser = new DOMParser();
39+
40+
/*
41+
* JSON data that we read from Django have been passed through
42+
* Django's marksafe function that escapes any HTML characters.
43+
* Use the DOMParser to decode these before we read parse the JSON.
44+
*/
45+
function decodeMarkedSafeText(text) {
46+
const dom = domParser.parseFromString(text, 'text/html');
47+
return dom.documentElement.textContent;
48+
}
49+
3850
export default function pluginMediatorFactory(facade) {
3951
/**
4052
* The Mediator object - registers and loads kolibri_modules and acts as
@@ -273,7 +285,7 @@ export default function pluginMediatorFactory(facade) {
273285
}
274286
let messageMap;
275287
try {
276-
messageMap = JSON.parse(messageElement.innerHTML.trim());
288+
messageMap = JSON.parse(decodeMarkedSafeText(messageElement.innerHTML.trim()));
277289
} catch (e) {
278290
logger.error(`Error parsing language assets for ${moduleName}`);
279291
}
@@ -344,7 +356,7 @@ export default function pluginMediatorFactory(facade) {
344356
for (const element of contentRendererElements) {
345357
const moduleName = element.getAttribute('data-viewer');
346358
try {
347-
const data = JSON.parse(element.innerHTML.trim());
359+
const data = JSON.parse(decodeMarkedSafeText(element.innerHTML.trim()));
348360
const presets = data.presets;
349361
const urls = data.urls;
350362
this.registerContentRenderer(moduleName, urls, presets);

0 commit comments

Comments
 (0)