diff --git a/config.js b/config.js index 138923a3..a50742aa 100755 --- a/config.js +++ b/config.js @@ -279,6 +279,12 @@ const schema = { format: String, default: '', allowDomainOverride: true + }, + allowFullURL: { + doc: 'If true, assets can be loaded from any remote URL', + format: Boolean, + default: true, + allowDomainOverride: true } } }, diff --git a/dadi/lib/handlers/css.js b/dadi/lib/handlers/css.js index 0a045893..d970bd99 100644 --- a/dadi/lib/handlers/css.js +++ b/dadi/lib/handlers/css.js @@ -24,6 +24,8 @@ const CSSHandler = function (format, req, { true ) + this.isExternalUrl = this.url.pathname.indexOf('http://') > 0 || this.url.pathname.indexOf('https://') > 0 + this.isCompressed = Boolean( this.options.compress || this.legacyURLOverrides.compress || @@ -66,6 +68,22 @@ CSSHandler.prototype.get = function () { {domain: this.req.__domain} ) + // Aborting the request if full remote URL is required and not enabled. + if ( + this.isExternalUrl && + ( + !config.get('assets.remote.enabled', this.req.__domain) || + !config.get('assets.remote.allowFullURL', this.req.__domain) + ) + ) { + let err = { + statusCode: 403, + message: 'Loading assets from a full remote URL is not supported by this instance of DADI CDN' + } + + return Promise.reject(err) + } + return this.storageHandler.get().then(stream => { return this.transform(stream) }).then(stream => { diff --git a/dadi/lib/handlers/default.js b/dadi/lib/handlers/default.js index e3e017c9..8ac9f2e5 100644 --- a/dadi/lib/handlers/default.js +++ b/dadi/lib/handlers/default.js @@ -22,6 +22,8 @@ const DefaultHandler = function (format, req, { true ) + this.isExternalUrl = this.url.pathname.indexOf('http://') > 0 || this.url.pathname.indexOf('https://') > 0 + this.cache = Cache() this.cacheKey = [req.__domain, this.url.href] @@ -52,6 +54,22 @@ DefaultHandler.prototype.get = function () { {domain: this.req.__domain} ) + // Aborting the request if full remote URL is required and not enabled. + if ( + this.isExternalUrl && + ( + !config.get('assets.remote.enabled', this.req.__domain) || + !config.get('assets.remote.allowFullURL', this.req.__domain) + ) + ) { + let err = { + statusCode: 403, + message: 'Loading assets from a full remote URL is not supported by this instance of DADI CDN' + } + + return Promise.reject(err) + } + return this.storageHandler.get().then(stream => { return this.cache.cacheFile(stream, this.cacheKey, { ttl: config.get('caching.ttl', this.req.__domain) diff --git a/dadi/lib/handlers/js.js b/dadi/lib/handlers/js.js index 12be8399..4a738ee1 100644 --- a/dadi/lib/handlers/js.js +++ b/dadi/lib/handlers/js.js @@ -27,6 +27,8 @@ const JSHandler = function (format, req, { true ) + this.isExternalUrl = this.url.pathname.indexOf('http://') > 0 || this.url.pathname.indexOf('https://') > 0 + this.cache = Cache() this.cacheKey = [req.__domain, this.url.href] @@ -63,6 +65,22 @@ JSHandler.prototype.get = function () { {domain: this.req.__domain} ) + // Aborting the request if full remote URL is required and not enabled. + if ( + this.isExternalUrl && + ( + !config.get('assets.remote.enabled', this.req.__domain) || + !config.get('assets.remote.allowFullURL', this.req.__domain) + ) + ) { + let err = { + statusCode: 403, + message: 'Loading assets from a full remote URL is not supported by this instance of DADI CDN' + } + + return Promise.reject(err) + } + return this.storageHandler.get().then(stream => { return this.transform(stream) }).then(stream => { diff --git a/test/acceptance/multi-domain.js b/test/acceptance/multi-domain.js index b372e84b..7723d0a9 100644 --- a/test/acceptance/multi-domain.js +++ b/test/acceptance/multi-domain.js @@ -333,7 +333,7 @@ describe('Multi-domain', function () { }) }).timeout(5000) - it('should use the allowFullURL setting defined at domain level to determine whether or not a request with a full remote URL will be served', done => { + it('should use the images.allowFullURL setting defined at domain level to determine whether or not a request with a full remote URL will be served', done => { config.set('images.remote.allowFullURL', true, 'localhost') config.set('images.remote.allowFullURL', false, 'testdomain.com') @@ -358,6 +358,81 @@ describe('Multi-domain', function () { }) }).timeout(5000) + it('should use the assets.allowFullURL setting defined at domain level to determine whether or not a CSS request with a full remote URL will be served', done => { + config.set('assets.remote.allowFullURL', true, 'localhost') + config.set('assets.remote.allowFullURL', false, 'testdomain.com') + + request(cdnUrl) + .get('/http://one.somedomain.tech/test.css') + .set('Host', 'localhost:80') + .expect(200) + .end((err, res) => { + res.headers['content-type'].should.eql('text/css') + + request(cdnUrl) + .get('/http://one.somedomain.tech/test.css') + .set('Host', 'testdomain.com:80') + .end((err, res) => { + res.statusCode.should.eql(403) + res.body.message.should.eql( + 'Loading assets from a full remote URL is not supported by this instance of DADI CDN' + ) + + done() + }) + }) + }).timeout(5000) + + it('should use the assets.allowFullURL setting defined at domain level to determine whether or not a JS request with a full remote URL will be served', done => { + config.set('assets.remote.allowFullURL', true, 'localhost') + config.set('assets.remote.allowFullURL', false, 'testdomain.com') + + request(cdnUrl) + .get('/http://one.somedomain.tech/test.js') + .set('Host', 'localhost:80') + .expect(200) + .end((err, res) => { + res.headers['content-type'].should.eql('application/javascript') + + request(cdnUrl) + .get('/http://one.somedomain.tech/test.js') + .set('Host', 'testdomain.com:80') + .end((err, res) => { + res.statusCode.should.eql(403) + res.body.message.should.eql( + 'Loading assets from a full remote URL is not supported by this instance of DADI CDN' + ) + + done() + }) + }) + }).timeout(5000) + + it('should use the assets.allowFullURL setting defined at domain level to determine whether or not a default request with a full remote URL will be served', done => { + config.set('assets.remote.allowFullURL', true, 'localhost') + config.set('assets.remote.allowFullURL', false, 'testdomain.com') + + request(cdnUrl) + .get('/http://one.somedomain.tech/test.txt') + .set('Host', 'localhost:80') + .expect(200) + .end((err, res) => { + res.headers['content-type'].should.eql('text/plain') + + request(cdnUrl) + .get('/http://one.somedomain.tech/test.txt') + .set('Host', 'testdomain.com:80') + .end((err, res) => { + res.statusCode.should.eql(403) + res.body.message.should.eql( + 'Loading assets from a full remote URL is not supported by this instance of DADI CDN' + ) + + done() + }) + }) + }).timeout(5000) + describe('when the target domain is not configured', () => { let testDomain = 'unknowndomain.com'