11'use strict'
22const NOT_FOUND = - 1
33const _ = require ( 'lodash' )
4+ const Joi = require ( '@hapi/joi' )
5+ const schema = require ( './schema' )
46
57module . exports = {
68 validateServiceProxies ( ) {
9+ const proxies = this . getAllServiceProxies ( )
10+
11+ const { error } = Joi . validate ( proxies , schema )
12+ if ( error ) {
13+ throw new this . serverless . classes . Error ( error . message )
14+ }
15+
716 const corsPreflight = { }
8- const events = this . getAllServiceProxies ( ) . map ( ( serviceProxy ) => {
17+
18+ const events = proxies . map ( ( serviceProxy ) => {
919 const serviceName = this . getServiceName ( serviceProxy )
10- this . checkAllowedService ( serviceName )
1120 const http = serviceProxy [ serviceName ]
12- http . path = this . getProxyPath ( serviceProxy [ serviceName ] , serviceName )
13- http . method = this . getProxyMethod ( serviceProxy [ serviceName ] , serviceName )
14- http . auth = this . getAuth ( serviceProxy [ serviceName ] , serviceName )
21+ http . path = http . path . replace ( / ^ \/ / , '' ) . replace ( / \/ $ / , '' )
22+ http . method = http . method . toLowerCase ( )
23+ http . auth = {
24+ authorizationType : http . authorizationType || 'NONE'
25+ }
1526
16- this . validateRequestParameters ( serviceProxy [ serviceName ] , serviceName )
27+ if ( _ . has ( http , 'authorizerId' ) ) {
28+ http . auth . authorizerId = http . authorizerId
29+ }
30+
31+ if ( _ . has ( http , 'authorizationScopes' ) ) {
32+ http . auth . authorizationScopes = http . authorizationScopes
33+ }
1734
1835 if ( serviceProxy [ serviceName ] . cors ) {
1936 http . cors = this . getCors ( serviceProxy [ serviceName ] )
@@ -47,49 +64,8 @@ module.exports = {
4764 }
4865 } ,
4966
50- checkAllowedService ( serviceName ) {
51- const allowedProxies = [ 'kinesis' , 'sqs' , 's3' , 'sns' ]
52- if ( allowedProxies . indexOf ( serviceName ) === NOT_FOUND ) {
53- const errorMessage = [
54- `Invalid APIG proxy "${ serviceName } ".` ,
55- ` This plugin supported Proxies are: ${ allowedProxies . join ( ', ' ) } .`
56- ] . join ( '' )
57- throw new this . serverless . classes . Error ( errorMessage )
58- }
59- } ,
60-
61- getProxyPath ( proxy , serviceName ) {
62- if ( proxy . path && _ . isString ( proxy . path ) ) {
63- return proxy . path . replace ( / ^ \/ / , '' ) . replace ( / \/ $ / , '' )
64- }
65-
66- throw new this . serverless . classes . Error (
67- `Missing or invalid "path" property in ${ serviceName } proxy`
68- )
69- } ,
70-
71- getProxyMethod ( proxy , serviceName ) {
72- if ( proxy . method && _ . isString ( proxy . method ) ) {
73- const method = proxy . method . toLowerCase ( )
74-
75- const allowedMethods = [ 'get' , 'post' , 'put' , 'patch' , 'options' , 'head' , 'delete' , 'any' ]
76- if ( allowedMethods . indexOf ( method ) === NOT_FOUND ) {
77- const errorMessage = [
78- `Invalid APIG method "${ proxy . method } " in AWS service proxy.` ,
79- ` AWS supported methods are: ${ allowedMethods . join ( ', ' ) } .`
80- ] . join ( '' )
81- throw new this . serverless . classes . Error ( errorMessage )
82- }
83- return method
84- }
85-
86- throw new this . serverless . classes . Error (
87- `Missing or invalid "method" property in ${ serviceName } proxy`
88- )
89- } ,
90-
9167 getCors ( proxy ) {
92- const headers = [
68+ const defaultHeaders = [
9369 'Content-Type' ,
9470 'X-Amz-Date' ,
9571 'Authorization' ,
@@ -102,34 +78,17 @@ module.exports = {
10278 origins : [ '*' ] ,
10379 origin : '*' ,
10480 methods : [ 'OPTIONS' ] ,
105- headers,
81+ headers : defaultHeaders ,
10682 allowCredentials : false
10783 }
10884
109- if ( typeof proxy . cors === 'object' ) {
85+ if ( _ . isPlainObject ( proxy . cors ) ) {
11086 cors = proxy . cors
11187 cors . methods = cors . methods || [ ]
11288 cors . allowCredentials = Boolean ( cors . allowCredentials )
11389
114- if ( cors . origins && cors . origin ) {
115- const errorMessage = [
116- 'You can only use "origin" or "origins",' ,
117- ' but not both at the same time to configure CORS.' ,
118- ' Please check the docs for more info.'
119- ] . join ( '' )
120- throw new this . serverless . classes . Error ( errorMessage )
121- }
122-
123- if ( cors . headers ) {
124- if ( ! Array . isArray ( cors . headers ) ) {
125- const errorMessage = [
126- 'CORS header values must be provided as an array.' ,
127- ' Please check the docs for more info.'
128- ] . join ( '' )
129- throw new this . serverless . classes . Error ( errorMessage )
130- }
131- } else {
132- cors . headers = headers
90+ if ( ! cors . headers ) {
91+ cors . headers = defaultHeaders
13392 }
13493
13594 if ( cors . methods . indexOf ( 'OPTIONS' ) === NOT_FOUND ) {
@@ -139,87 +98,10 @@ module.exports = {
13998 if ( cors . methods . indexOf ( proxy . method . toUpperCase ( ) ) === NOT_FOUND ) {
14099 cors . methods . push ( proxy . method . toUpperCase ( ) )
141100 }
142-
143- if ( _ . has ( cors , 'maxAge' ) ) {
144- if ( ! _ . isInteger ( cors . maxAge ) || cors . maxAge < 1 ) {
145- const errorMessage = 'maxAge should be an integer over 0'
146- throw new this . serverless . classes . Error ( errorMessage )
147- }
148- }
149101 } else {
150102 cors . methods . push ( proxy . method . toUpperCase ( ) )
151103 }
152104
153105 return cors
154- } ,
155-
156- getAuth ( proxy , serviceName ) {
157- const auth = {
158- authorizationType : 'NONE'
159- }
160-
161- if ( ! _ . isUndefined ( proxy . authorizationType ) ) {
162- if ( _ . isString ( proxy . authorizationType ) ) {
163- const allowedTypes = [ 'NONE' , 'AWS_IAM' , 'CUSTOM' , 'COGNITO_USER_POOLS' ]
164- if ( allowedTypes . indexOf ( proxy . authorizationType ) === NOT_FOUND ) {
165- const errorMessage = [
166- `Invalid APIG authorization type "${ proxy . authorizationType } " in AWS service proxy.` ,
167- ` AWS supported types are: ${ allowedTypes . join ( ', ' ) } .`
168- ] . join ( '' )
169- throw new this . serverless . classes . Error ( errorMessage )
170- }
171-
172- auth . authorizationType = proxy . authorizationType
173- } else {
174- throw new this . serverless . classes . Error (
175- `Invalid "authorizationType" property in ${ serviceName } proxy`
176- )
177- }
178- }
179-
180- if ( ! _ . isUndefined ( proxy . authorizerId ) ) {
181- if ( auth . authorizationType !== 'CUSTOM' ) {
182- const errorMessage = `Expecting 'CUSTOM' authorization type when 'authorizerId' is set in service ${ serviceName } `
183- throw new this . serverless . classes . Error ( errorMessage )
184- }
185-
186- auth . authorizerId = proxy . authorizerId
187- }
188-
189- if ( ! _ . isUndefined ( proxy . authorizationScopes ) ) {
190- if ( _ . isArray ( proxy . authorizationScopes ) ) {
191- if ( auth . authorizationType !== 'COGNITO_USER_POOLS' ) {
192- const errorMessage = `Expecting 'COGNITO_USER_POOLS' authorization type when 'authorizationScopes' is set in service ${ serviceName } `
193- throw new this . serverless . classes . Error ( errorMessage )
194- }
195-
196- auth . authorizationScopes = proxy . authorizationScopes
197- } else {
198- throw new this . serverless . classes . Error (
199- `Invalid "authorizationScopes" property in ${ serviceName } proxy`
200- )
201- }
202- }
203-
204- return auth
205- } ,
206-
207- validateRequestParameters ( proxy , serviceName ) {
208- if ( ! _ . isUndefined ( proxy . requestParameters ) ) {
209- if ( serviceName !== 'sqs' ) {
210- throw new this . serverless . classes . Error (
211- 'requestParameters property is only valid for "sqs" service proxy'
212- )
213- }
214-
215- if (
216- ! _ . isPlainObject ( proxy . requestParameters ) ||
217- _ . some ( _ . values ( proxy . requestParameters ) , ( v ) => ! _ . isString ( v ) )
218- ) {
219- throw new this . serverless . classes . Error (
220- 'requestParameters property must be a string to string mapping'
221- )
222- }
223- }
224106 }
225107}
0 commit comments