|
|
@@ -0,0 +1,97 @@
|
|
|
+/**
|
|
|
+ * 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+};
|