0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

🐛 🎨 Improves AMP validation for video and iframe (#7270)

no issue

Video tags aren't supported in Amperize yet, therefore, we strip them out. If a `<video>` tag has nested `<source>` elements, they would stay because they are whitelisted regarding `Sanitize`, as we use them for `<audio>` tags as well.

This PR uses `cheerio` to strip out in `<video>` nested `<source>` tags, without removing the fallback text.
It also removes prohibites attributes for `<amp-iframe>` which are e. g. used by Vimeo embeds.

Removes every kind of inline `style` attributes, as they will cause validation errors as well.
This commit is contained in:
Aileen Nowak 2016-08-25 12:47:28 +02:00 committed by Katharina Irrgang
parent 7932f63e6a
commit d59f199ee3
2 changed files with 80 additions and 3 deletions

View file

@ -13,6 +13,7 @@ var hbs = require('express-hbs'),
sanitizeHtml = require('sanitize-html'), sanitizeHtml = require('sanitize-html'),
config = require('../../../../config'), config = require('../../../../config'),
makeAbsoluteUrl = require('../../../../utils/make-absolute-urls'), makeAbsoluteUrl = require('../../../../utils/make-absolute-urls'),
cheerio = require('cheerio'),
amperize = new Amperize(), amperize = new Amperize(),
amperizeCache = {}, amperizeCache = {},
allowedAMPTags = [], allowedAMPTags = [],
@ -67,9 +68,31 @@ function ampContent() {
}; };
return Promise.props(amperizeHTML).then(function (result) { return Promise.props(amperizeHTML).then(function (result) {
var $;
// our Amperized HTML
ampHTML = result.amperize || ''; ampHTML = result.amperize || '';
// let's sanitize our HTML!!! // Use cheerio to traverse through HTML and make little clean-ups
$ = cheerio.load(ampHTML);
// We have to remove source children in video, as source
// is whitelisted for audio, but causes validation
// errors in video, because video will be stripped out.
// @TODO: remove this, when Amperize support video transform
$('video').children('source').remove();
// Vimeo iframe e. g. come with prohibited attributes
// @TODO: remove this, when Amperize supports HTML sanitizing
$('amp-iframe').removeAttr('webkitallowfullscreen');
$('amp-iframe').removeAttr('mozallowfullscreen');
// No inline style allowed
$('*').removeAttr('style');
ampHTML = $.html();
// @TODO: remove this, when Amperize supports HTML sanitizing
cleanHTML = sanitizeHtml(ampHTML, { cleanHTML = sanitizeHtml(ampHTML, {
allowedTags: allowedAMPTags, allowedTags: allowedAMPTags,
allowedAttributes: false, allowedAttributes: false,

View file

@ -136,12 +136,66 @@ describe('{{amp_content}} helper', function () {
it('can transform audio tags to amp-audio', function (done) { it('can transform audio tags to amp-audio', function (done) {
var testData = { var testData = {
html: '<audio controls="controls" width="auto" height="50" autoplay="mobile">Your browser does not support the <code>audio</code> element.<source src="https://audio.com/foo.wav" type="audio/wav"></audio>' + html: '<audio controls="controls" width="auto" height="50" autoplay="mobile">Your browser does not support the <code>audio</code> element.<source src="https://audio.com/foo.wav" type="audio/wav"></audio>' +
'<audio src="http://audio.com/foo.ogg"><track kind="captions" src="http://audio.com/foo.en.vtt" srclang="en" label="English"><track kind="captions" src="http://audio.com/foo.sv.vtt" srclang="sv" label="Svenska"></audio>', '<audio src="http://audio.com/foo.ogg"><track kind="captions" src="http://audio.com/foo.en.vtt" srclang="en" label="English"><source kind="captions" src="http://audio.com/foo.sv.vtt" srclang="sv" label="Svenska"></audio>',
updated_at: 'Wed Jul 27 2016 18:17:22 GMT+0200 (CEST)', updated_at: 'Wed Jul 27 2016 18:17:22 GMT+0200 (CEST)',
id: 1 id: 1
}, },
expectedResult = '<amp-audio controls="controls" width="auto" height="50" autoplay="mobile">Your browser does not support the <code>audio</code> element.<source src="https://audio.com/foo.wav" type="audio/wav" /></amp-audio>' + expectedResult = '<amp-audio controls="controls" width="auto" height="50" autoplay="mobile">Your browser does not support the <code>audio</code> element.<source src="https://audio.com/foo.wav" type="audio/wav" /></amp-audio>' +
'<amp-audio src="https://audio.com/foo.ogg"><track kind="captions" src="https://audio.com/foo.en.vtt" srclang="en" label="English" /><track kind="captions" src="https://audio.com/foo.sv.vtt" srclang="sv" label="Svenska" /></amp-audio>', '<amp-audio src="https://audio.com/foo.ogg"><track kind="captions" src="https://audio.com/foo.en.vtt" srclang="en" label="English" /><source kind="captions" src="https://audio.com/foo.sv.vtt" srclang="sv" label="Svenska" /></amp-audio>',
ampResult = ampContentHelper.call(testData);
ampResult.then(function (rendered) {
should.exist(rendered);
rendered.string.should.equal(expectedResult);
done();
}).catch(done);
});
it('removes video tags including source children', function (done) {
var testData = {
html: '<video width="480" controls poster="https://archive.org/download/WebmVp8Vorbis/webmvp8.gif" >' +
'<source src="https://archive.org/download/WebmVp8Vorbis/webmvp8.webm" type="video/webm">' +
'<source src="https://archive.org/download/WebmVp8Vorbis/webmvp8_512kb.mp4" type="video/mp4">' +
'Your browser doesn\'t support HTML5 video tag.' +
'</video>',
updated_at: 'Wed Jul 27 2016 18:17:22 GMT+0200 (CEST)',
id: 1
},
expectedResult = 'Your browser doesn\'t support HTML5 video tag.',
ampResult = ampContentHelper.call(testData);
ampResult.then(function (rendered) {
should.exist(rendered);
rendered.string.should.equal(expectedResult);
done();
}).catch(done);
});
it('removes inline style', function (done) {
var testData = {
html: '<amp-img src="/content/images/2016/08/aileen_small.jpg" style="border-radius: 50%" width="50" height="50" layout="responsive"></amp-img>',
updated_at: 'Wed Jul 27 2016 18:17:22 GMT+0200 (CEST)',
id: 1
},
expectedResult = '<amp-img src="https://my-awesome-blog.com/content/images/2016/08/aileen_small.jpg" width="50" height="50" layout="responsive"></amp-img>',
ampResult = ampContentHelper.call(testData);
ampResult.then(function (rendered) {
should.exist(rendered);
rendered.string.should.equal(expectedResult);
done();
}).catch(done);
});
it('removes prohibited iframe attributes', function (done) {
var testData = {
html: '<iframe src="https://player.vimeo.com/video/180069681?color=ffffff" width="640" height="267" frameborder="0" ' +
'webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>',
updated_at: 'Wed Jul 27 2016 18:17:22 GMT+0200 (CEST)',
id: 1
},
expectedResult = '<amp-iframe src="https://player.vimeo.com/video/180069681?color=ffffff" width="640" height="267" ' +
'frameborder="0" allowfullscreen sandbox="allow-scripts allow-same-origin" layout="responsive"></amp-iframe>',
ampResult = ampContentHelper.call(testData); ampResult = ampContentHelper.call(testData);
ampResult.then(function (rendered) { ampResult.then(function (rendered) {