Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

amperize

Package Overview
Dependencies
Maintainers
3
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

amperize - npm Package Compare versions

Comparing version 0.3.4 to 0.3.5

137

lib/amperize.js
'use strict';
var merge = require('lodash.merge')
, EventEmitter = require('events').EventEmitter
var EventEmitter = require('events').EventEmitter
, emits = require('emits')

@@ -11,5 +10,6 @@ , html = require('htmlparser2')

, url = require('url')
, http = require('http')
, https = require('https')
, got = require('got')
, _ = require('lodash')
, sizeOf = require('image-size')
, validator = require('validator')
, helpers = require('./helpers');

@@ -36,4 +36,2 @@

var called;
/**

@@ -49,3 +47,3 @@ * Amperizer constructor. Borrows from Minimize.

function Amperize(options) {
this.config = merge({}, DEFAULTS, options || {});
this.config = _.merge({}, DEFAULTS, options || {});
this.emits = emits;

@@ -111,6 +109,2 @@

function close(error, html) {
if (error) {
return step(error);
}
html += helpers.close(element);

@@ -121,6 +115,2 @@ step(null, html);

function enter(error) {
if (error) {
return step(error);
}
children = element.children;

@@ -137,17 +127,17 @@ html += helpers[element.type](element);

function useSecureSchema(element) {
if (element.attribs && element.attribs.src) {
// Every src attribute must be with 'https' protocol otherwise it will not get validated by AMP.
// If we're unable to replace it, we will deal with the valitation error, but at least
// we tried.
if (element.attribs.src.indexOf('https://') === -1) {
if (element.attribs.src.indexOf('http://') === 0) {
// Replace 'http' with 'https', so the validation passes
element.attribs.src = element.attribs.src.replace(/^http:\/\//i, 'https://');
} else if (element.attribs.src.indexOf('//') === 0) {
// Giphy embedded iFrames are without protocol and start with '//', so at least
// we can fix those cases.
element.attribs.src = 'https:' + element.attribs.src;
}
}
if (element.attribs && element.attribs.src) {
// Every src attribute must be with 'https' protocol otherwise it will not get validated by AMP.
// If we're unable to replace it, we will deal with the valitation error, but at least
// we tried.
if (element.attribs.src.indexOf('https://') === -1) {
if (element.attribs.src.indexOf('http://') === 0) {
// Replace 'http' with 'https', so the validation passes
element.attribs.src = element.attribs.src.replace(/^http:\/\//i, 'https://');
} else if (element.attribs.src.indexOf('//') === 0) {
// Giphy embedded iFrames are without protocol and start with '//', so at least
// we can fix those cases.
element.attribs.src = 'https:' + element.attribs.src;
}
}
}

@@ -179,48 +169,51 @@ return;

function getImageSize(element) {
var options = url.parse(element.attribs.src),
timeout = 5000,
request = element.attribs.src.indexOf('https') === 0 ? https : http;
var imageObj = url.parse(element.attribs.src),
requestOptions,
timeout = 3000;
called = false;
if (!validator.isURL(imageObj.href)) {
// revert this element, do not show
element.name = 'img';
return enter();
}
// We need the user-agent, otherwise some https request may fail (e. g. cloudfare)
options.headers = { 'User-Agent': 'Mozilla/5.0' };
requestOptions = {
headers: {
'User-Agent': 'Mozilla/5.0'
},
timeout: timeout,
encoding: null
};
return request.get(options, function (response) {
var chunks = [];
response.on('data', function (chunk) {
chunks.push(chunk);
}).on('end', function () {
try {
var dimensions = sizeOf(Buffer.concat(chunks));
element.attribs.width = dimensions.width;
element.attribs.height = dimensions.height;
return got (
imageObj.href,
requestOptions
).then(function (response) {
try {
// Using the Buffer rather than an URL requires to use sizeOf synchronously.
// See https://github.com/image-size/image-size#asynchronous
var dimensions = sizeOf(response.body);
return getLayoutAttribute(element);
} catch (err) {
if (called) return;
called = true;
var e = new Error();
e.message = err.message || err;
e.src = element.attribs.src
return enter(e);
}
});
}).on('socket', function (socket) {
socket.setTimeout(timeout);
socket.on('timeout', function () {
if (called) return;
called = true;
var e = new Error();
e.message = 'Timeout while trying to fetch image sizes.';
e.src = element.attribs.src
return enter(e);
});
}).on('error', function (error) {
if (called) return;
called = true;
var e = new Error();
e.message = error.message || error;
e.src = element.attribs.src
return enter(e);
// CASE: `.ico` files might have multiple images and therefore multiple sizes.
// We return the largest size found (image-size default is the first size found)
if (dimensions.images) {
dimensions.width = _.maxBy(dimensions.images, function (w) {return w.width;}).width;
dimensions.height = _.maxBy(dimensions.images, function (h) {return h.height;}).height;
}
element.attribs.width = dimensions.width;
element.attribs.height = dimensions.height;
return getLayoutAttribute(element);
} catch (err) {
// revert this element, do not show
element.name = 'img';
return enter();
}
}).catch(function (err) {
// revert this element, do not show
element.name = 'img';
return enter();
});

@@ -239,3 +232,3 @@ }

if (element.attribs.src.indexOf('http') === 0) {
return getImageSize(element);
return getImageSize(element);
}

@@ -265,3 +258,3 @@ }

if (element.name === 'audio') {
element.name = 'amp-audio';
element.name = 'amp-audio';
}

@@ -268,0 +261,0 @@

{
"name": "amperize",
"version": "0.3.4",
"version": "0.3.5",
"description": "AMP up your plain HTML",

@@ -28,19 +28,21 @@ "main": "./lib/amperize",

"dependencies": {
"async": "2.1.4",
"emits": "3.0.0",
"htmlparser2": "3.9.2",
"async": "^2.1.4",
"emits": "^3.0.0",
"got": "^7.1.0",
"htmlparser2": "^3.9.2",
"image-size": "0.5.1",
"lodash.merge": "4.6.0",
"lodash": "^4.17.4",
"nock": "^9.0.2",
"rewire": "^2.5.2",
"uuid": "^3.0.0"
"uuid": "^3.0.0",
"validator": "^8.2.0"
},
"devDependencies": {
"chai": "3.5.0",
"chai": "^3.5.0",
"cz-conventional-changelog": "1.2.0",
"istanbul": "0.4.5",
"mocha": "3.2.0",
"istanbul": "^0.4.5",
"mocha": "^3.2.0",
"semantic-release": "6.3.2",
"sinon": "1.17.7",
"sinon-chai": "2.8.0"
"sinon": "^1.17.7",
"sinon-chai": "^2.8.0"
},

@@ -47,0 +49,0 @@ "config": {

@@ -98,3 +98,3 @@ 'use strict';

.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});

@@ -107,3 +107,2 @@

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-img');

@@ -123,3 +122,3 @@ expect(result).to.contain('src="http://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256"');

.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});

@@ -132,3 +131,2 @@

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-img');

@@ -144,2 +142,78 @@ expect(result).to.contain('src="http://static.wixstatic.com/media/355241_d31358572a2542c5a44738ddcb59e7ea.jpg_256"');

it('transforms <img> into <amp-img></amp-img> when width and height is set and overwrites it', function (done) {
sizeOfMock = nock('http://somestockwebsite.com')
.get('/image.jpg')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 350, height: 200, type: 'jpg'});
Amperize.__set__('sizeOf', sizeOfStub);
amperize.parse('<img src="http://somestockwebsite.com/image.jpg" width="100" height="50">', function (error, result) {
expect(result).to.exist;
expect(result).to.contain('<amp-img');
expect(result).to.contain('src="http://somestockwebsite.com/image.jpg"');
expect(result).to.contain('layout="responsive"');
expect(result).to.contain('width="350"');
expect(result).to.contain('height="200"');
expect(result).to.contain('</amp-img>');
done();
});
});
it('transforms <img> into <amp-img></amp-img> does not overwrite layout attribute', function (done) {
sizeOfMock = nock('http://somestockwebsite.com')
.get('/image.jpg')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 350, height: 200, type: 'jpg'});
Amperize.__set__('sizeOf', sizeOfStub);
amperize.parse('<img src="http://somestockwebsite.com/image.jpg" layout="fixed">', function (error, result) {
expect(result).to.exist;
expect(result).to.contain('<amp-img');
expect(result).to.contain('src="http://somestockwebsite.com/image.jpg"');
expect(result).to.contain('layout="fixed"');
expect(result).to.contain('width="350"');
expect(result).to.contain('height="200"');
expect(result).to.contain('</amp-img>');
done();
});
});
it('returns largest image value for .ico files', function (done) {
sizeOfMock = nock('https://somewebsite.com')
.get('/favicon.ico')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({
width: 32,
height: 32,
type: 'ico',
images: [
{width: 48, height: 48},
{width: 32, height: 32},
{width: 16, height: 16}
]
});
Amperize.__set__('sizeOf', sizeOfStub);
amperize.parse('<img src="https://somewebsite.com/favicon.ico">', function (error, result) {
expect(result).to.exist;
expect(result).to.contain('<amp-img');
expect(result).to.contain('src="https://somewebsite.com/favicon.ico"');
expect(result).to.contain('layout="fixed"');
expect(result).to.contain('width="48"');
expect(result).to.contain('height="48"');
expect(result).to.contain('</amp-img>');
done();
});
});
it('transforms .gif <img> with only height property into <amp-anim></amp-anim> with full dimensions by overriding them', function (done) {

@@ -149,3 +223,3 @@ sizeOfMock = nock('https://media.giphy.com')

.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});

@@ -158,3 +232,2 @@

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-anim');

@@ -170,6 +243,5 @@ expect(result).to.contain('src="https://media.giphy.com/media/l46CtzgjhTm29Cbjq/giphy.gif"');

it('transforms <iframe> with only width property into <amp-iframe></amp-iframe> with full dimensions withour overriding them', function (done) {
it('transforms <iframe> with only width property into <amp-iframe></amp-iframe> with full dimensions without overriding them', function (done) {
amperize.parse('<iframe src="https://www.youtube.com/embed/HMQkV5cTuoY" width="400"></iframe>', function (error, result) {
expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-iframe');

@@ -186,2 +258,30 @@ expect(result).to.contain('src="https://www.youtube.com/embed/HMQkV5cTuoY"');

it('transforms <iframe> with only height property into <amp-iframe></amp-iframe> with full dimensions without overriding them', function (done) {
amperize.parse('<iframe src="https://www.youtube.com/embed/HMQkV5cTuoY" height="400"></iframe>', function (error, result) {
expect(result).to.exist;
expect(result).to.contain('<amp-iframe');
expect(result).to.contain('src="https://www.youtube.com/embed/HMQkV5cTuoY"');
expect(result).to.contain('layout="responsive"');
expect(result).to.contain('width="600"');
expect(result).to.contain('height="400"');
expect(result).to.contain('</amp-iframe>');
expect(result).to.contain('sandbox="allow-scripts allow-same-origin"')
done();
});
});
it('transforms <iframe> with sandbox property into <amp-iframe></amp-iframe> with full dimensions without overriding them', function (done) {
amperize.parse('<iframe src="https://www.youtube.com/embed/HMQkV5cTuoY" sandbox="allow-scripts"></iframe>', function (error, result) {
expect(result).to.exist;
expect(result).to.contain('<amp-iframe');
expect(result).to.contain('src="https://www.youtube.com/embed/HMQkV5cTuoY"');
expect(result).to.contain('layout="responsive"');
expect(result).to.contain('width="600"');
expect(result).to.contain('height="400"');
expect(result).to.contain('</amp-iframe>');
expect(result).to.contain('sandbox="allow-scripts"')
done();
});
});
it('adds \'https\' protocol to <iframe> if no protocol is supplied (e. e. giphy)', function (done) {

@@ -191,3 +291,2 @@ var url = '<iframe src="//giphy.com/embed/3oEduKP4VaUxJvLwuA" width="480" height="372" frameBorder="0" class="giphy-embed" allowFullScreen></iframe>';

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-iframe');

@@ -208,3 +307,2 @@ expect(result).to.contain('src="https://giphy.com/embed/3oEduKP4VaUxJvLwuA"');

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-iframe');

@@ -224,3 +322,2 @@ expect(result).to.contain('src="https://giphy.com/embed/3oEduKP4VaUxJvLwuA"');

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-img');

@@ -239,3 +336,2 @@ expect(result).to.contain('src="/content/images/IMG_xyz.jpg"');

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.be.equal('<img><p>some text here</p>');

@@ -246,6 +342,13 @@ done();

it('can handle invalid URLs', function (done) {
amperize.parse('<img src="http:not-a-website">', function (error, result) {
expect(result).to.exist;
expect(result).to.be.equal('<img src="http:not-a-website">');
done();
});
});
it('can handle <iframe> tag without src and does not transform it', function (done) {
amperize.parse('<iframe>', function (error, result) {
expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.be.equal('<iframe></iframe>');

@@ -259,3 +362,2 @@ done();

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-audio src="https://foo.mp3" autoplay="">');

@@ -271,3 +373,2 @@ expect(result).to.contain('Your browser does not support the <code>audio</code> element.');

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-audio');

@@ -284,3 +385,2 @@ expect(result).to.contain('controls="controls" width="auto" height="50" autoplay="mobile"');

expect(result).to.exist;
expect(Amperize.__get__('called')).to.be.equal(false);
expect(result).to.contain('<amp-audio src="foo.ogg">');

@@ -294,13 +394,41 @@ expect(result).to.contain('<track kind="captions" src="https://foo.en.vtt" srclang="en" label="English">');

it('can handle redirects', function (done) {
var secondSizeOfMock;
sizeOfMock = nock('http://noimagehere.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(301, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
},
{
location: 'http://someredirectedurl.com/files/f/feedough/x/11/1540353_20925115.jpg'
});
secondSizeOfMock = nock('http://someredirectedurl.com')
.get('/files/f/feedough/x/11/1540353_20925115.jpg')
.reply(200, {
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.returns({width: 100, height: 100, type: 'jpg'});
Amperize.__set__('sizeOf', sizeOfStub);
amperize.parse('<img src="http://noimagehere.com/files/f/feedough/x/11/1540353_20925115.jpg">', function (error, result) {
expect(sizeOfMock.isDone()).to.be.equal(true);
expect(secondSizeOfMock.isDone()).to.be.equal(true);
expect(error).to.be.null;
expect(result).to.contain('<amp-img src="http://noimagehere.com/files/f/feedough/x/11/1540353_20925115.jpg" width="100" height="100" layout="fixed"></amp-img>');
done();
});
});
it('can handle request errors', function (done) {
var callCounts;
sizeOfMock = nock('http://example.com')
.get('/images/IMG_xyz.jpg')
.replyWithError('something awful happened');
.reply(404, {message: 'something awful happened', code: 'AWFUL_ERROR'});
amperize.parse('<img src="http://example.com/images/IMG_xyz.jpg">', function (error, result) {
expect(Amperize.__get__('called')).to.be.equal(true);
expect(error).to.exist;
expect(error.message).to.contain('something awful happened');
expect(result).to.not.exist;
expect(error).to.be.null;
expect(result).to.contain('<img src="http://example.com/images/IMG_xyz.jpg');
done();

@@ -314,12 +442,10 @@ });

.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
sizeOfStub.throws('error');
sizeOfStub.throws({error: 'image-size could not find dimensions'});
Amperize.__set__('sizeOf', sizeOfStub);
amperize.parse('<img src="http://example.com/images/IMG_xyz.jpg">', function (error, result) {
expect(Amperize.__get__('called')).to.be.equal(true);
expect(error).to.exist;
expect(error.message.name).to.contain('error');
expect(result).to.not.exist;
expect(error).to.be.null;
expect(result).to.contain('<img src="http://example.com/images/IMG_xyz.jpg');
done();

@@ -330,14 +456,14 @@ });

it('can handle timeout errors', function (done) {
this.timeout(3500);
sizeOfMock = nock('http://example.com')
.get('/images/IMG_xyz.jpg')
.socketDelay(5500)
.delay(3500)
.reply(200, {
data: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
body: '<Buffer 2c be a4 40 f7 87 73 1e 57 2c c1 e4 0d 79 03 95 42 f0 42 2e 41 95 27 c9 5c 35 a7 71 2c 09 5a 57 d3 04 1e 83 03 28 07 96 b0 c8 88 65 07 7a d1 d6 63 50>'
});
amperize.parse('<img src="http://example.com/images/IMG_xyz.jpg">', function (error, result) {
expect(Amperize.__get__('called')).to.be.equal(true);
expect(error).to.exist;
expect(error.message).to.contain('Timeout while trying to fetch image sizes.');
expect(result).to.not.exist;
expect(error).to.be.null;
expect(result).to.contain('<img src="http://example.com/images/IMG_xyz.jpg');
done();

@@ -344,0 +470,0 @@ });

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc