vandium
Advanced tools
Comparing version 7.0.0-Beta2 to 7.0.0-Beta3
@@ -120,3 +120,2 @@ /** | ||
//: path || '/.well-known/jwks.json', | ||
function useJwks( options ) { | ||
@@ -139,23 +138,39 @@ | ||
const { provider, ...details } = options; | ||
const { provider, jwk, ...details } = options; | ||
let jwksClient; | ||
let key; | ||
switch( provider ) { | ||
if( provider || details.hostname ) { | ||
case 'auth0': | ||
jwksClient = Provider.Auth0( { ...details } ); | ||
break; | ||
let jwksClient; | ||
case 'awscognito': | ||
jwksClient = Provider.AWSCognito( { ...details } ); | ||
break; | ||
switch( provider ) { | ||
default: | ||
jwksClient = client( { ...details }); | ||
case 'auth0': | ||
jwksClient = Provider.Auth0( { ...details } ); | ||
break; | ||
case 'awscognito': | ||
jwksClient = Provider.AWSCognito( { ...details } ); | ||
break; | ||
default: | ||
jwksClient = client( { ...details }); | ||
} | ||
const jwks = jwksClient.getSync(); | ||
key = jwks.keys[0]; // use first key | ||
} | ||
else if( jwk ) { | ||
const jwks = jwksClient.getSync(); | ||
key = { ...jwk }; | ||
} | ||
currentConfig.jwk = jwks.keys[0]; // use first key | ||
if( !key ) { | ||
throw new Error( 'Missing key for proper configuration in useJwks()' ); | ||
} | ||
currentConfig.jwk = key; | ||
} | ||
@@ -183,2 +198,22 @@ | ||
function load() { | ||
const { jwks, jwk } = getConfig(); | ||
if( !jwk && jwks ) { | ||
// load jwks | ||
useJwks(); | ||
} | ||
} | ||
function isEnabled() { | ||
const { jwks, jwk, jwt } = getConfig(); | ||
const enabled = ( !!jwks || jwk || (Object.keys( jwt ).length > 0) ); | ||
return enabled; | ||
} | ||
module.exports = { | ||
@@ -191,2 +226,6 @@ | ||
useJwks, | ||
load, | ||
isEnabled, | ||
}; |
@@ -1,2 +0,2 @@ | ||
const { getConfig, useJwks } = require( './auth' ); | ||
const { getConfig, useJwks, load, isEnabled } = require( './auth' ); | ||
@@ -7,2 +7,4 @@ module.exports = { | ||
useJwks, | ||
load, | ||
isEnabled, | ||
}; |
@@ -24,2 +24,4 @@ /** | ||
lambda.features = Object.freeze( handler.features() ); | ||
return lambda; | ||
@@ -26,0 +28,0 @@ } |
@@ -24,10 +24,10 @@ | ||
'methodValidation', | ||
'eventNormalization', | ||
'bodyProcessing', | ||
'protection', | ||
'cookies', | ||
'jwt', | ||
'validation', | ||
'extractExecutor' | ||
'methodValidation', | ||
'eventNormalization', | ||
'bodyProcessing', | ||
'protection', | ||
'cookies', | ||
'jwt', | ||
'validation', | ||
'extractExecutor' | ||
]; | ||
@@ -37,253 +37,257 @@ | ||
constructor( options = {} ) { | ||
constructor( options = {} ) { | ||
super( 'apigateway', options ); | ||
super( 'apigateway', options ); | ||
this._initPipeline(); | ||
this._initPipeline(); | ||
this.authorization( false ); | ||
this.authorization( false ); | ||
this.bodyEncoding( options.bodyEncoding ); | ||
this.bodyEncoding( options.bodyEncoding ); | ||
this._headers = {}; | ||
this._headers = {}; | ||
this.protection( options.protection ); | ||
this.protection( options.protection ); | ||
this._onErrorHandler = (err) => err; | ||
this.afterFunc = function() {}; | ||
} | ||
this._onErrorHandler = (err) => err; | ||
this.afterFunc = function() {}; | ||
} | ||
authorization( authConfig ) { | ||
authorization( authConfig ) { | ||
return this.jwt( authConfig ); | ||
} | ||
return this.jwt( authConfig ); | ||
} | ||
jwt( options = {} ) { | ||
jwt( options = {} ) { | ||
const jwt = new JWTValidator( options ); | ||
const jwt = new JWTValidator( options ); | ||
this.pipeline.stage( 'jwt', ( { event } ) => { | ||
this.pipeline.stage( 'jwt', ( { event } ) => { | ||
jwt.validate( event ); | ||
}); | ||
jwt.validate( event ); | ||
}); | ||
return this; | ||
} | ||
this.setFeature( 'jwt', jwt.features() ); | ||
formURLEncoded( enabled = true ) { | ||
return this; | ||
} | ||
return this.bodyEncoding( enabled ? 'formURLEncoded' : 'auto' ); | ||
} | ||
formURLEncoded( enabled = true ) { | ||
skipBodyParse() { | ||
return this.bodyEncoding( enabled ? 'formURLEncoded' : 'auto' ); | ||
} | ||
return this.bodyEncoding( 'none' ); | ||
} | ||
skipBodyParse() { | ||
bodyEncoding( encoding = 'auto' ) { | ||
return this.bodyEncoding( 'none' ); | ||
} | ||
this.pipeline.stage( 'bodyProcessing', (state) => { | ||
bodyEncoding( encoding = 'auto' ) { | ||
const { event } = state; | ||
this.pipeline.stage( 'bodyProcessing', (state) => { | ||
if( event.body ) { | ||
const { event } = state; | ||
event.rawBody = event.body; | ||
if( event.body ) { | ||
event.body = processBody( event.body, encoding ); | ||
} | ||
}); | ||
event.rawBody = event.body; | ||
return this; | ||
} | ||
event.body = processBody( event.body, encoding ); | ||
} | ||
}); | ||
headers( values = {} ) { | ||
this.setFeature( 'bodyEncoding', { encoding } ); | ||
for( let name in values ) { | ||
return this; | ||
} | ||
this.header( name, values[ name ] ); | ||
} | ||
headers( values = {} ) { | ||
return this; | ||
for( let name in values ) { | ||
this.header( name, values[ name ] ); | ||
} | ||
header( name, value ) { | ||
return this; | ||
} | ||
processHeaderValue( this._headers, name, value ); | ||
header( name, value ) { | ||
return this; | ||
} | ||
processHeaderValue( this._headers, name, value ); | ||
protection( options ) { | ||
return this; | ||
} | ||
this._protection = new Protection( options ); | ||
protection( options ) { | ||
return this; | ||
} | ||
this._protection = new Protection( options ); | ||
cors( options = { | ||
return this; | ||
} | ||
allowOrigin: '*', | ||
allowCredentials: true | ||
}) { | ||
cors( options = { allowOrigin: '*', allowCredentials: true } ) { | ||
const headerListValue = ( value ) => { | ||
const headerListValue = ( value ) => { | ||
if( Array.isArray( value ) ) { | ||
if( Array.isArray( value ) ) { | ||
value = value.join( ', ' ); | ||
} | ||
value = value.join( ', ' ); | ||
} | ||
return value; | ||
}; | ||
return value; | ||
}; | ||
this.header( 'Access-Control-Allow-Origin', options.allowOrigin ); | ||
this.header( 'Access-Control-Allow-Credentials', options.allowCredentials ); | ||
this.header( 'Access-Control-Expose-Headers', headerListValue( options.exposeHeaders ) ); | ||
this.header( 'Access-Control-Max-Age', options.maxAge ); | ||
this.header( 'Access-Control-Allow-Headers', headerListValue( options.allowHeaders ) ); | ||
this.header( 'Access-Control-Allow-Origin', options.allowOrigin ); | ||
this.header( 'Access-Control-Allow-Credentials', options.allowCredentials ); | ||
this.header( 'Access-Control-Expose-Headers', headerListValue( options.exposeHeaders ) ); | ||
this.header( 'Access-Control-Max-Age', options.maxAge ); | ||
this.header( 'Access-Control-Allow-Headers', headerListValue( options.allowHeaders ) ); | ||
return this; | ||
} | ||
return this; | ||
} | ||
onError( onErrorHandler ) { | ||
onError( onErrorHandler ) { | ||
this._onErrorHandler = onErrorHandler; | ||
this._onErrorHandler = onErrorHandler; | ||
return this; | ||
} | ||
this.setFeature( 'onError', { enabled: !!this._onErrorHandler } ); | ||
currentMethodHandler() { | ||
return this; | ||
} | ||
throw new Error( 'not implemented' ); | ||
} | ||
currentMethodHandler() { | ||
validation( functionOrOptions ) { | ||
throw new Error( 'not implemented' ); | ||
} | ||
let options = functionOrOptions; | ||
validation( functionOrOptions ) { | ||
if( isFunction( functionOrOptions ) ) { | ||
let options = functionOrOptions; | ||
options = functionOrOptions( types ); | ||
} | ||
if( isFunction( functionOrOptions ) ) { | ||
this.currentMethodHandler().setValidation( options ); | ||
return this; | ||
options = functionOrOptions( types ); | ||
} | ||
handler( handler ) { | ||
this.currentMethodHandler().setValidation( options ); | ||
this.currentMethodHandler().setHandler( handler ); | ||
this.setFeature( 'validation', { enabled: true } ); | ||
return this; | ||
} | ||
return this; | ||
} | ||
onResponse( onResponseHandler ) { | ||
handler( handler ) { | ||
this.currentMethodHandler().setOnResponse( onResponseHandler ); | ||
this.currentMethodHandler().setHandler( handler ); | ||
return this; | ||
} | ||
return this; | ||
} | ||
addMethodsToHandler( lambdaHandler ) { | ||
onResponse( onResponseHandler ) { | ||
super.addMethodsToHandler( lambdaHandler ); | ||
this.currentMethodHandler().setOnResponse( onResponseHandler ); | ||
[ | ||
// 'jwt', | ||
// 'authorization', | ||
'formURLEncoded', | ||
'header', | ||
'headers', | ||
'protection', | ||
'cors', | ||
'onError', | ||
'onResponse', | ||
'validation', | ||
// 'handler' | ||
return this; | ||
} | ||
].forEach( (handlerMethod) => this.addlambdaHandlerMethod( handlerMethod, lambdaHandler)); | ||
} | ||
addMethodsToHandler( lambdaHandler ) { | ||
executePreprocessors( state ) { | ||
super.addMethodsToHandler( lambdaHandler ); | ||
super.executePreprocessors( state ); | ||
[ | ||
// 'jwt', | ||
// 'authorization', | ||
'formURLEncoded', | ||
'header', | ||
'headers', | ||
'protection', | ||
'cors', | ||
'onError', | ||
'onResponse', | ||
'validation', | ||
// 'handler' | ||
//execute pipeline | ||
this.pipeline.executorSync().run( state ); | ||
} | ||
].forEach( (handlerMethod) => this.addlambdaHandlerMethod( handlerMethod, lambdaHandler)); | ||
} | ||
async processResult( result, context, { methodHandler } ) { | ||
executePreprocessors( state ) { | ||
const responseObject = responseProcessor.processResult( result, context, this._headers ); | ||
super.executePreprocessors( state ); | ||
return await this.processResponse( responseObject, methodHandler ); | ||
} | ||
//execute pipeline | ||
this.pipeline.executorSync().run( state ); | ||
} | ||
async processError( error, context, { methodHandler } ) { | ||
async processResult( result, context, { methodHandler } ) { | ||
let updatedError = await this._onErrorHandler( error, context.event, context ); | ||
const responseObject = responseProcessor.processResult( result, context, this._headers ); | ||
if( updatedError ) { | ||
return await this.processResponse( responseObject, methodHandler ); | ||
} | ||
error = updatedError; | ||
} | ||
async processError( error, context, { methodHandler } ) { | ||
const responseObject = responseProcessor.processError( error, this._headers ); | ||
let updatedError = await this._onErrorHandler( error, context.event, context ); | ||
return await this.processResponse( responseObject, methodHandler ); | ||
if( updatedError ) { | ||
error = updatedError; | ||
} | ||
/** | ||
* Single conduit to processing responses | ||
*/ | ||
async processResponse( responseObject, methodHandler ) { | ||
const responseObject = responseProcessor.processError( error, this._headers ); | ||
let { result } = responseObject; | ||
return await this.processResponse( responseObject, methodHandler ); | ||
} | ||
if( methodHandler ) { | ||
/** | ||
* Single conduit to processing responses | ||
*/ | ||
async processResponse( responseObject, methodHandler ) { | ||
result = await methodHandler.onResponse( result ); | ||
} | ||
let { result } = responseObject; | ||
return { result }; | ||
if( methodHandler ) { | ||
result = await methodHandler.onResponse( result ); | ||
} | ||
_initPipeline() { | ||
return { result }; | ||
} | ||
this.pipeline = new Pipeline( PREPROCESSOR_PIPELINE_STAGES ); | ||
_initPipeline() { | ||
this.pipeline.stage( 'eventNormalization', ( { event }) => { | ||
this.pipeline = new Pipeline( PREPROCESSOR_PIPELINE_STAGES ); | ||
event.queryStringParameters = event.queryStringParameters || {}; | ||
event.multiValueQueryStringParameters = event.multiValueQueryStringParameters || {}; | ||
this.pipeline.stage( 'eventNormalization', ( { event }) => { | ||
event.pathParameters = event.pathParameters || {}; | ||
}); | ||
event.queryStringParameters = event.queryStringParameters || {}; | ||
event.multiValueQueryStringParameters = event.multiValueQueryStringParameters || {}; | ||
this.pipeline.stage( 'protection', ( { event }) => { | ||
event.pathParameters = event.pathParameters || {}; | ||
}); | ||
this._protection.validate( event ); | ||
}); | ||
this.pipeline.stage( 'protection', ( { event }) => { | ||
this.pipeline.stage( 'cookies', ( { event }) => { | ||
this._protection.validate( event ); | ||
}); | ||
event.cookies = processCookies( event.headers ); | ||
}); | ||
this.pipeline.stage( 'cookies', ( { event }) => { | ||
this.pipeline.stage( 'validation', ( { event, extra: { methodHandler } } ) => { | ||
event.cookies = processCookies( event.headers ); | ||
}); | ||
methodHandler.validator.validate( event ); | ||
}); | ||
this.pipeline.stage( 'validation', ( { event, extra: { methodHandler } } ) => { | ||
this.pipeline.stage( 'extractExecutor', (state) => { | ||
methodHandler.validator.validate( event ); | ||
}); | ||
const { extra: { methodHandler } } = state; | ||
this.pipeline.stage( 'extractExecutor', (state) => { | ||
state.executor = methodHandler.executor; | ||
}); | ||
} | ||
const { extra: { methodHandler } } = state; | ||
state.executor = methodHandler.executor; | ||
}); | ||
} | ||
} | ||
module.exports = BaseAPIHandler; |
@@ -5,4 +5,8 @@ const APIHandler = require( './api_handler' ); | ||
const { isEnabled: isAuthEnabled, load: loadAuth } = require( '../../auth' ); | ||
function api( options ) { | ||
loadAuth(); | ||
return new APIHandler( options ).createLambda(); | ||
@@ -13,3 +17,13 @@ } | ||
return new APIGateway().handler( handler ); | ||
const instance = new APIGateway().handler( handler ); | ||
if( isAuthEnabled() ) { | ||
loadAuth(); | ||
// enabled auth | ||
instance.requiresAuthorization(); | ||
} | ||
return instance; | ||
} | ||
@@ -16,0 +30,0 @@ |
@@ -140,4 +140,20 @@ const { applyValues, parseBoolean, valueFromPath } = require( '../../utils' ); | ||
} | ||
features() { | ||
const f = { enabled: this.enabled }; | ||
if( this.enabled ) { | ||
f.algorithm = this.algorithm; | ||
f.tokenPath = this.tokenPath; | ||
f.xsrf = this.xsrf; | ||
f.xsrfClaimPath = this.xsrfClaimPath; | ||
f.xsrfTokenPath = this.xsrfTokenPath; | ||
} | ||
return f; | ||
} | ||
} | ||
module.exports = JWTValidator; |
@@ -61,5 +61,17 @@ const utils = require( '../utils' ); | ||
this._features = {}; | ||
this.eventProcessor( (event) => event ); | ||
} | ||
setFeature( name, featureProps ) { | ||
this._features[ name ] = featureProps; | ||
} | ||
features() { | ||
return { ...this._features }; | ||
} | ||
addMethodsToHandler( lambdaHandler ) { | ||
@@ -70,2 +82,4 @@ | ||
this.addlambdaHandlerMethod( 'finally', lambdaHandler ); | ||
lambdaHandler.features = () => this.features(); | ||
} | ||
@@ -218,3 +232,3 @@ | ||
_createPipeline() { | ||
const pipeline = new Pipeline( [ 'preprocessors', 'validateExecutor', 'beforeHandler', 'runHandler' ] ); | ||
@@ -221,0 +235,0 @@ |
{ | ||
"name": "vandium", | ||
"version": "7.0.0-Beta2", | ||
"version": "7.0.0-Beta3", | ||
"description": "AWS Lambda framework for building functions using Node.js for API Gateway, IoT applications, and other AWS events", | ||
@@ -66,3 +66,3 @@ "main": "lib/index.js", | ||
"app-root-path": "^3.0.0", | ||
"aws-sdk": "^2.620.0", | ||
"aws-sdk": "latest", | ||
"chai": "^4.1.2", | ||
@@ -72,3 +72,3 @@ "dotenv": "^8.2.0", | ||
"eslint": "^6.8.0", | ||
"eslint-plugin-mocha": "^6.2.2", | ||
"eslint-plugin-mocha": "^6.3.0", | ||
"freshy": "^1.0.2", | ||
@@ -82,5 +82,5 @@ "jwt-builder": "^1.0.0", | ||
"proxyquire": "^2.1.3", | ||
"sinon": "^8.1.1", | ||
"sinon": "^9.0.0", | ||
"uuid": "^3.4.0" | ||
} | ||
} |
74079
1873