Repository: serverless/serverless (JavaScript)
Date: 2020-03-18 16:29:09+00:00
Task type: Bug Fix

Issue:
"cors: true" default origin wildcard removed by `generateCorsResponseTemplate`
# Bug Report

## Description

<!-- Please use https://forum.serverless.com, StackOverflow or other forums for Q&A -->
<!-- Please answer ALL the question below. Otherwise we probably have to close the issue due to missing information -->

1. What did you do?
In the process of updating to a newer version of serverless (v1.31 to v1.62) I expected the cors behavior to stay the same. I have `cors: true` set to receive all the defaults.

1. What happened?
After deploying the wildcard was missing from `Access-Control-Allow-Origin` and all preflights are failing.

![Screen Shot 2020-03-10 at 9 18 54 AM](https://user-images.githubusercontent.com/5738268/76327451-0542f480-62b8-11ea-940a-10857fc189a0.png)

1. What should've happened?
After deploying nothing should have changed when upgrading serverless. I would still expect to see the `cors: true` setting all of the defaults as described in documentation: https://serverless.com/framework/docs/providers/aws/events/apigateway#enabling-cors

1. What's the content of your `serverless.yml` file?
```
functions:
  myFunction:
    description: Description of function.
    handler: handler.myFunction
    timeout: 25
    events:
      - http:
          path: my/path
          method: get
          cors: true
```

1. What's the output you get when you use the `SLS_DEBUG=*` environment variable (e.g. `SLS_DEBUG=* serverless deploy`)
Everything looks as expected - no errors are thrown.



Findings
When trying to diagnose what was happening - the 'override' message in the screenshot above (from the API Gateway Console) led me to the functions `generateCorsResponseTemplate` and `regexifyWildcards` in `cors.js`. 

![Screen Shot 2020-03-10 at 10 17 11 AM](https://user-images.githubusercontent.com/5738268/76328581-78993600-62b9-11ea-9491-97d928bf3d5d.png)

If that generated code in AWS is updated to `$origin.matches(".+")` then I get the expected outcome `"Access-Control-Allow-Origin":"*"`.
A possible solution could be updating `.*` to `.+` in the function `regexifyWildcards` in `cors.js`. So when `cors: true` the defaults remain as expected.



Issue discussion:
Yeah, any code that does a regex match on `.*` is suspect.

Looks like this one's generated via dynamic programming: https://github.com/serverless/serverless/blob/master/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js#L140

Might be hard to write a good unit test for. Is that... VTL?
@Bhuser thanks for reporting.

It looks that regression was introduced with #5740 (cc @richarddd)

PR with a fix is welcome

Solution patch:
diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js
index b45dee786e2..dd010ccf3aa 100644
--- a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js
+++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js
@@ -126,12 +126,12 @@ module.exports = {
   },
 
   regexifyWildcards(orig) {
-    return orig.map(str => str.replace(/\./g, '[.]').replace('*', '.*'));
+    return orig.map(str => str.replace(/\./g, '[.]').replace('*', '.+'));
   },
 
   generateCorsResponseTemplate(origins) {
     // glob pattern needs to be parsed into a Java regex
-    // escape literal dots, replace wildcard * for .*
+    // escape literal dots, replace wildcard * for .+
     const regexOrigins = this.regexifyWildcards(origins);
 
     return (


Test patch:
diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js
index c81e2f107fc..fa3cb783df4 100644
--- a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js
+++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js
@@ -107,7 +107,7 @@ describe('#compileCors()', () => {
           .ApiGatewayMethodUsersCreateOptions.Properties.Integration.IntegrationResponses[0]
           .ResponseTemplates['application/json']
       ).to.equal(
-        '#set($origin = $input.params("Origin"))\n#if($origin == "") #set($origin = $input.params("origin")) #end\n#if($origin.matches("http://localhost:3000") || $origin.matches("https://.*[.]example[.]com")) #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin) #end'
+        '#set($origin = $input.params("Origin"))\n#if($origin == "") #set($origin = $input.params("origin")) #end\n#if($origin.matches("http://localhost:3000") || $origin.matches("https://.+[.]example[.]com")) #set($context.responseOverride.header.Access-Control-Allow-Origin = $origin) #end'
       );
 
       expect(
diff --git a/tests/integration-all/api-gateway/tests.js b/tests/integration-all/api-gateway/tests.js
index f926a9f117b..06488851511 100644
--- a/tests/integration-all/api-gateway/tests.js
+++ b/tests/integration-all/api-gateway/tests.js
@@ -113,8 +113,7 @@ describe('AWS - API Gateway Integration Test', function() {
         expect(headers.get('access-control-allow-headers')).to.equal(allowHeaders);
         expect(headers.get('access-control-allow-methods')).to.equal('OPTIONS,GET');
         expect(headers.get('access-control-allow-credentials')).to.equal(null);
-        // TODO: for some reason this test fails for now...
-        // expect(headers.get('access-control-allow-origin')).to.equal('*');
+        expect(headers.get('access-control-allow-origin')).to.equal('*');
       });
     });