Skip to content

Commit

Permalink
fix(FEC-13362): sanitize captions (#163)
Browse files Browse the repository at this point in the history
* fix(FEC-13361): sanitize captions

* fix(FEC-13361): fix tests
  • Loading branch information
semarche-kaltura committed Oct 23, 2023
1 parent e3f1bc2 commit aa0c288
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 95 deletions.
61 changes: 61 additions & 0 deletions cypress/e2e/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
export const preparePage = (pluginConf: Object, playbackConf: Object) => {
cy.visit('index.html');
return cy.window().then(win => {
try {
// @ts-ignore
var kalturaPlayer = win.KalturaPlayer.setup({
targetId: 'player-placeholder',
provider: {
partnerId: -1,
env: {
cdnUrl: 'http://mock-cdn',
serviceUrl: 'http://mock-api'
}
},
plugins: {
'playkit-js-transcript': pluginConf,
uiManagers: {},
kalturaCuepoints: {}
},
playback: {muted: true, autoplay: true, ...playbackConf}
});
return kalturaPlayer.loadMedia({entryId: '0_wifqaipd'});
} catch (e: any) {
return Promise.reject(e.message);
}
});
};

export const getPlayer = () => {
// @ts-ignore
return cy.window().then($win => $win.KalturaPlayer.getPlayers()['player-placeholder']);
};

export const loadPlayer = (pluginConf = {}, playbackConf = {}) => {
return preparePage(pluginConf, playbackConf).then(() => getPlayer().then(kalturaPlayer => kalturaPlayer));
};

export const clickTranscriptPluginButton = () => {
cy.get('[data-testid="transcript_pluginButton"]').should('exist');
cy.get('[data-testid="transcript_pluginButton"]').click({force: true});
};

export const clickClosePluginButton = () => {
cy.get('[data-testid="transcriptCloseButton"] button').should('exist');
cy.get('[data-testid="transcriptCloseButton"] button').click({force: true});
};

const checkRequest = (reqBody: any, service: string, action: string) => {
return reqBody?.service === service && reqBody?.action === action;
};

export const mockKalturaBe = (entryFixture = 'vod-with-captions.json', captionsFixture = 'captions-en-response.json') => {
cy.intercept('http://mock-api/service/multirequest', req => {
if (checkRequest(req.body[2], 'baseEntry', 'list')) {
return req.reply({fixture: entryFixture});
}
if (checkRequest(req.body[2], 'caption_captionasset', 'serveAsJson')) {
return req.reply({fixture: captionsFixture});
}
});
};
97 changes: 24 additions & 73 deletions cypress/e2e/transcript.cy.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {mockKalturaBe, loadPlayer, clickClosePluginButton} from './env';

const MANIFEST = `#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="audio",LANGUAGE="en",NAME="English",AUTOSELECT=YES,DEFAULT=YES,URI="${location.origin}/media/index_1.m3u8",SUBTITLES="subs"
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=509496,RESOLUTION=480x272,AUDIO="audio",SUBTITLES="subs"
Expand All @@ -8,67 +10,9 @@ const MANIFEST_SAFARI = `#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=504265,RESOLUTION=480x272,AUDIO="audio",SUBTITLES="subs"
${location.origin}/media/index.m3u8`;

const preparePage = (pluginConf: Object, playbackConf: Object) => {
cy.visit('index.html');
return cy.window().then(win => {
try {
// @ts-ignore
var kalturaPlayer = win.KalturaPlayer.setup({
targetId: 'player-placeholder',
provider: {
partnerId: -1,
env: {
cdnUrl: 'http://mock-cdn',
serviceUrl: 'http://mock-api'
}
},
plugins: {
'playkit-js-transcript': pluginConf,
uiManagers: {},
kalturaCuepoints: {}
},
playback: {muted: true, autoplay: true, ...playbackConf}
});
return kalturaPlayer.loadMedia({entryId: '0_wifqaipd'});
} catch (e: any) {
return Promise.reject(e.message);
}
});
};

const getPlayer = () => {
// @ts-ignore
return cy.window().then($win => $win.KalturaPlayer.getPlayers()['player-placeholder']);
};

const loadPlayer = (pluginConf = {}, playbackConf = {}) => {
return preparePage(pluginConf, playbackConf).then(() => getPlayer().then(kalturaPlayer => kalturaPlayer));
};

const clickTranscriptPluginButton = () => {
cy.get('[data-testid="transcript_pluginButton"]').should('exist');
cy.get('[data-testid="transcript_pluginButton"]').click({force: true});
};

const clickClosePluginButton = () => {
cy.get('[data-testid="transcriptCloseButton"] button').should('exist');
cy.get('[data-testid="transcriptCloseButton"] button').click({force: true});
};

const checkRequest = (reqBody: any, service: string, action: string) => {
return reqBody?.service === service && reqBody?.action === action;
};

const mockKalturaBe = (entryFixture = 'vod-with-captions.json', captionsFixture = 'captions-en-response.json') => {
cy.intercept('http://mock-api/service/multirequest', req => {
if (checkRequest(req.body[2], 'baseEntry', 'list')) {
return req.reply({fixture: entryFixture});
}
if (checkRequest(req.body[2], 'caption_captionasset', 'serveAsJson')) {
return req.reply({fixture: captionsFixture});
}
});
};
Cypress.on('uncaught:exception', (err, runnable) => {
return false;
});

describe('Transcript plugin', () => {
beforeEach(() => {
Expand Down Expand Up @@ -116,18 +60,25 @@ describe('Transcript plugin', () => {
});
});

// it('should select captions and highlight them', () => {
// mockKalturaBe();
// loadPlayer().then(kalturaPlayer => {
// const captionSpan = cy.get('[data-testid="transcript_list"] [role="listitem"]').first();
// captionSpan.should('exist');
// kalturaPlayer.currentTime = 20;
// captionSpan.should('have.attr', 'aria-current', 'false');
// captionSpan.click();
// kalturaPlayer.pause();
// captionSpan.should('have.attr', 'aria-current', 'true');
// });
// });
it('should select captions and highlight them', () => {
mockKalturaBe();
loadPlayer().then(kalturaPlayer => {
kalturaPlayer.currentTime = 5;
cy.get('[data-testid="transcript_list"]').within(() => {
kalturaPlayer.pause();
const caption = cy.contains('first caption');
caption.should('exist');
caption.parent().invoke('attr', 'class').should('contain', 'highlighted');
});
});
});

it('should sanitize html tags', () => {
mockKalturaBe();
loadPlayer({showTime: false}).then(() => {
cy.get('[aria-label="Dark Side."]').should('have.text', 'Dark Side.');
});
});

it('should close plugin if ESC button pressed', () => {
mockKalturaBe();
Expand Down
48 changes: 28 additions & 20 deletions cypress/public/ui-conf.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"@playkit-js/common": "^1.2.13",
"@playkit-js/playkit-js-ui": "^0.77.3",
"@playkit-js/ui-managers": "^1.3.11",
"sanitize-html": "^2.11.0",
"stream-browserify": "^3.0.0"
},
"kaltura": {
Expand Down
2 changes: 1 addition & 1 deletion src/components/caption/caption.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component, h} from 'preact';
import {A11yWrapper, OnClickEvent} from '@playkit-js/common/dist/hoc/a11y-wrapper';
import {A11yWrapper} from '@playkit-js/common/dist/hoc/a11y-wrapper';
import {secondsToTime} from '../../utils';
import {CuePointData} from '../../types';
import * as styles from './caption.scss';
Expand Down
11 changes: 10 additions & 1 deletion src/transcript-plugin.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// @ts-ignore
import * as sanitizeHtml from 'sanitize-html';
import {h} from 'preact';
import {OnClickEvent} from '@playkit-js/common/dist/hoc/a11y-wrapper';
import {ui} from '@playkit-js/kaltura-player-js';
Expand Down Expand Up @@ -149,7 +151,7 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {

private _addCaptionData = (newData: CuePointData[]) => {
this._activeCaptionMapId = this._getCaptionMapId();
this._captionMap.set(this._activeCaptionMapId, newData);
this._captionMap.set(this._activeCaptionMapId, this._sanitizeCaptions(newData));
this._isLoading = false;
clearTimeout(this._loadingTimeoutId);
this._updateTranscriptPanel();
Expand Down Expand Up @@ -199,6 +201,13 @@ export class TranscriptPlugin extends KalturaPlayer.core.BasePlugin {
}
};

private _sanitizeCaptions = (data: CuePointData[]) => {
return data.map(caption => ({
...caption,
text: sanitizeHtml(caption.text || '', {allowedTags: []})
}));
};

private _addTranscriptItem(): void {
if (Math.max(this._transcriptPanel, this._transcriptIcon) > 0) {
// transcript panel or icon already exist
Expand Down
91 changes: 91 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,11 @@ decompress-response@^3.3.0:
dependencies:
mimic-response "^1.0.0"

deepmerge@^4.2.2:
version "4.3.1"
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==

default-gateway@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
Expand Down Expand Up @@ -1801,6 +1806,36 @@ dns-packet@^5.2.2:
dependencies:
"@leichtgewicht/ip-codec" "^2.0.1"

dom-serializer@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.2"
entities "^4.2.0"

domelementtype@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==

domhandler@^5.0.2, domhandler@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
dependencies:
domelementtype "^2.3.0"

domutils@^3.0.1:
version "3.1.0"
resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
dependencies:
dom-serializer "^2.0.0"
domelementtype "^2.3.0"
domhandler "^5.0.3"

dot-prop@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
Expand Down Expand Up @@ -1898,6 +1933,11 @@ enquirer@^2.3.6:
dependencies:
ansi-colors "^4.1.1"

entities@^4.2.0, entities@^4.4.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==

envinfo@^7.7.3:
version "7.8.1"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475"
Expand Down Expand Up @@ -1937,6 +1977,11 @@ escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==

escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==

eslint-scope@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
Expand Down Expand Up @@ -2561,6 +2606,16 @@ html-entities@^2.3.2:
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46"
integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==

htmlparser2@^8.0.0:
version "8.0.2"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
dependencies:
domelementtype "^2.3.0"
domhandler "^5.0.3"
domutils "^3.0.1"
entities "^4.4.0"

http-cache-semantics@3.8.1:
version "3.8.1"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2"
Expand Down Expand Up @@ -2857,6 +2912,11 @@ is-plain-object@^2.0.4:
dependencies:
isobject "^3.0.1"

is-plain-object@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==

is-retry-allowed@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
Expand Down Expand Up @@ -3487,6 +3547,11 @@ nanoid@^3.3.4:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==

nanoid@^3.3.6:
version "3.3.6"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c"
integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==

negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
Expand Down Expand Up @@ -3743,6 +3808,11 @@ parse-json@^5.0.0:
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"

parse-srcset@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==

parseurl@~1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
Expand Down Expand Up @@ -3915,6 +3985,15 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==

postcss@^8.3.11:
version "8.4.31"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
dependencies:
nanoid "^3.3.6"
picocolors "^1.0.0"
source-map-js "^1.0.2"

postcss@^8.4.7:
version "8.4.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
Expand Down Expand Up @@ -4356,6 +4435,18 @@ safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0,
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==

sanitize-html@^2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.11.0.tgz#9a6434ee8fcaeddc740d8ae7cd5dd71d3981f8f6"
integrity sha512-BG68EDHRaGKqlsNjJ2xUB7gpInPA8gVx/mvjO743hZaeMCZ2DwzW7xvsqZ+KNU4QKwj86HJ3uu2liISf2qBBUA==
dependencies:
deepmerge "^4.2.2"
escape-string-regexp "^4.0.0"
htmlparser2 "^8.0.0"
is-plain-object "^5.0.0"
parse-srcset "^1.0.2"
postcss "^8.3.11"

sass-loader@^12.6.0:
version "12.6.0"
resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb"
Expand Down

0 comments on commit aa0c288

Please sign in to comment.