/** * CORS middleware for koa2 * * @param {Object} [options] * - {String|Function(ctx)} origin `Access-Control-Allow-Origin`, default is request Origin header * - {Array} exposeHeaders `Access-Control-Expose-Headers` * - {String|Number} maxAge `Access-Control-Max-Age` in seconds * - {Boolean} credentials `Access-Control-Allow-Credentials` * - {Array} allowMethods `Access-Control-Allow-Methods`, * default is ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] * - {Array} allowHeaders `Access-Control-Allow-Headers` * @return {Function} * @api public */ module.exports = function crossOrigin(options = {}) { const defaultOptions = { allowMethods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'] }; // set defaultOptions to options options = Object.assign({}, defaultOptions, options); // eslint-disable-line no-param-reassign // eslint-disable-next-line consistent-return return async function cors(ctx, next) { // always set vary Origin Header // https://github.com/rs/cors/issues/10 ctx.vary('Origin'); let origin; if (typeof options.origin === 'function') { origin = options.origin(ctx); } else { origin = options.origin || ctx.get('Origin') || '*'; } if (!origin) { return await next(); } // Access-Control-Allow-Origin ctx.set('Access-Control-Allow-Origin', origin); if (ctx.method === 'OPTIONS') { // Preflight Request if (!ctx.get('Access-Control-Request-Method')) { return await next(); } // Access-Control-Max-Age if (options.maxAge) { ctx.set('Access-Control-Max-Age', String(options.maxAge)); } // Access-Control-Allow-Credentials if (options.credentials === true) { // When used as part of a response to a preflight request, // this indicates whether or not the actual request can be made using credentials. ctx.set('Access-Control-Allow-Credentials', 'true'); } // Access-Control-Allow-Methods if (options.allowMethods) { ctx.set('Access-Control-Allow-Methods', options.allowMethods.join(',')); } // Access-Control-Allow-Headers if (options.allowHeaders) { ctx.set('Access-Control-Allow-Headers', options.allowHeaders.join(',')); } else { ctx.set('Access-Control-Allow-Headers', ctx.get('Access-Control-Request-Headers')); } ctx.status = 204; // No Content } else { // Request // Access-Control-Allow-Credentials if (options.credentials === true) { if (origin === '*') { // `credentials` can't be true when the `origin` is set to `*` ctx.remove('Access-Control-Allow-Credentials'); } else { ctx.set('Access-Control-Allow-Credentials', 'true'); } } // Access-Control-Expose-Headers if (options.exposeHeaders) { ctx.set('Access-Control-Expose-Headers', options.exposeHeaders.join(',')); } try { await next(); } catch (err) { throw err; } } }; };