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:
parent
7932f63e6a
commit
d59f199ee3
2 changed files with 80 additions and 3 deletions
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue