diff --git a/lib/swagger.js b/lib/swagger.js index bcf3e07..7b5644c 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -12,6 +12,7 @@ var urlJoin = require('./url-join'); var _defaults = require('lodash.defaults'); var classHelper = require('./class-helper'); var routeHelper = require('./route-helper'); +var cors = require('cors'); /** * Create a remotable Swagger module for plugging into `RemoteObjects`. @@ -38,6 +39,8 @@ function Swagger(loopbackApplication, swaggerApp, opts) { var routes = adapter.allRoutes(); var classes = remotes.classes(); + setupCors(swaggerApp, remotes); + // These are the docs we will be sending from the /swagger endpoints. var resourceDoc = generateResourceDoc(opts); var apiDocs = {}; @@ -70,13 +73,20 @@ function Swagger(loopbackApplication, swaggerApp, opts) { }); /** - * The topmost Swagger resource is a description of all (non-Swagger) - * resources available on the system, and where to find more + * The topmost Swagger resource is a description of all (non-Swagger) + * resources available on the system, and where to find more * information about them. */ addRoute(swaggerApp, opts.resourcePath, resourceDoc, opts); } +function setupCors(swaggerApp, remotes) { + var corsOptions = remotes.options && remotes.options.cors || + { origin: true, credentials: true }; + + swaggerApp.use(cors(corsOptions)); +} + /** * Add a route to this remoting extension. * @param {Application} app Express application. diff --git a/package.json b/package.json index e1cde4a..a8e43fc 100644 --- a/package.json +++ b/package.json @@ -31,10 +31,11 @@ "url": "https://github.com/strongloop/loopback-explorer/blob/master/LICENSE" }, "dependencies": { - "swagger-ui": "~2.0.18", + "cors": "^2.4.2", "debug": "~1.0.3", + "express": "3.x", "lodash.clonedeep": "^2.4.1", "lodash.defaults": "^2.4.1", - "express": "3.x" + "swagger-ui": "~2.0.18" } } diff --git a/test/swagger.test.js b/test/swagger.test.js index 1cd0a5b..b07f0bb 100644 --- a/test/swagger.test.js +++ b/test/swagger.test.js @@ -106,6 +106,31 @@ describe('swagger definition', function() { }); }); + describe('Cross-origin resource sharing', function() { + it('allows cross-origin requests by default', function(done) { + var app = mountSwagger(); + request(app) + .options('/explorer/resources') + .set('Origin', 'http://example.com/') + .expect('Access-Control-Allow-Origin', /^http:\/\/example.com\/|\*/) + .expect('Access-Control-Allow-Methods', /\bGET\b/) + .end(done); + }); + + it('can be disabled by configuration', function(done) { + var app = mountSwagger({}, { remoting: { cors: { origin: false } } }); + request(app) + .options('/explorer/resources') + .end(function(err, res) { + if (err) return done(err); + var allowOrigin = res.get('Access-Control-Allow-Origin'); + expect(allowOrigin, 'Access-Control-Allow-Origin') + .to.equal(undefined); + done(); + }); + }); + }); + function getSwaggerResources(app, restPath, classPath) { return request(app) .get(urlJoin(restPath || '/explorer', '/resources', classPath || '')) @@ -122,6 +147,7 @@ describe('swagger definition', function() { addlOptions = addlOptions || {}; var app = createLoopbackAppWithModel(addlOptions.apiRoot); var swaggerApp = express(); + if (addlOptions.remoting) app.set('remoting', addlOptions.remoting); swagger(app, swaggerApp, options); app.use(addlOptions.explorerRoot || '/explorer', swaggerApp); return app;