From b509549e7cc9fdf1eb71f957c1580bc57093f929 Mon Sep 17 00:00:00 2001 From: listenrightmeow Date: Wed, 8 Jul 2020 18:13:57 -0700 Subject: [PATCH] tsconfig deep alias path corrections, auth0 authorizer test initial test case --- __tests__/authorizers/auth0.spec.ts | 45 +++++++++++++++++++ src/authorizers/auth0.ts | 32 ++++++------- src/helpers/i18n/authorizer.ts | 4 -- src/helpers/interfaces/{index.ts => all.ts} | 0 .../types/{router/index.ts => router.ts} | 0 src/i18n/authorizer.ts | 4 ++ tsconfig.json | 4 +- wallaby.js | 5 ++- webpack.config.js | 1 + 9 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 __tests__/authorizers/auth0.spec.ts delete mode 100644 src/helpers/i18n/authorizer.ts rename src/helpers/interfaces/{index.ts => all.ts} (100%) rename src/helpers/types/{router/index.ts => router.ts} (100%) create mode 100644 src/i18n/authorizer.ts diff --git a/__tests__/authorizers/auth0.spec.ts b/__tests__/authorizers/auth0.spec.ts new file mode 100644 index 0000000..5c7bf01 --- /dev/null +++ b/__tests__/authorizers/auth0.spec.ts @@ -0,0 +1,45 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ + +const sinon = require('sinon'); + +// import { authorize, decodeToken } from '@authorizers/auth0'; +import { expect } from 'chai'; +// import { SigningKeyNotFoundError } from 'jwks-rsa'; +import * as jwt from 'jsonwebtoken'; + +import { decodeToken } from '@authorizers/auth0'; +import { Responses as lang } from '@i18n/authorizer'; + +describe('auth0-authorizer', () => { + describe('decode', () => { + const sandbox = sinon.createSandbox(); + + afterEach(function () { + sandbox.restore(); + }); + + it('should return error', () => { + sandbox.stub(jwt, 'decode').throws(new Error()); + const callback = sinon.spy(); + + decodeToken('token', callback); + expect(callback.getCall(0).args).to.include(lang.ERROR); + }); + + it('should execute callback function', () => { + sandbox.stub(jwt, 'decode').returns(false); + const callback = sinon.spy(); + + decodeToken('token', callback); + expect(callback.getCall(0).args).to.include(lang.UNAUTHORIZED); + }); + + it('should return successfully', () => { + sandbox.stub(jwt, 'decode').returns(true); + const callback = sinon.spy(); + + const ctx = decodeToken('token', callback); + expect(ctx).to.be.true; + }); + }); +}); \ No newline at end of file diff --git a/src/authorizers/auth0.ts b/src/authorizers/auth0.ts index 938c0aa..a36054e 100644 --- a/src/authorizers/auth0.ts +++ b/src/authorizers/auth0.ts @@ -5,8 +5,8 @@ import { Context } from 'aws-lambda'; import * as jwt from 'jsonwebtoken'; import * as jwksClient from 'jwks-rsa'; -import * as lang from '@helpers/i18n/authorizer'; -import { Authorizer, Callback } from '@helpers/interfaces'; +import { Responses as lang } from '@i18n/authorizer'; +import { Authorizer, Callback } from '@helpers/interfaces/all'; export const authorize = (event: any, _context: Context, callback: Callback): void => { const authToken = stripTokenFromHeader(event, callback); @@ -19,11 +19,11 @@ export const authorize = (event: any, _context: Context, callback: Callback): vo authenticateToken(authClient, authToken, decodedToken.header.kid, event, callback); } -const authenticateToken = (authClient: any, authToken: string, decodedToken: string, event: any, callback: Callback) => { +export const authenticateToken = (authClient: any, authToken: string, decodedToken: string, event: any, callback: Callback) => { authClient.getSigningKey(decodedToken, (error: any, key: any) => { if (error) { - console.error(error); - return callback(new Error(lang.INTERNAL_SERVER_ERROR)); + console.error('ERROR', error); + return callback(lang.ERROR); } else { const signingKey: string = getSigningKey(key); @@ -32,20 +32,21 @@ const authenticateToken = (authClient: any, authToken: string, decodedToken: str algorithms: process.env.A0_ALGORITHM }, (error, decoded) => { if (error) { - return callback(new Error(lang.UNAUTHORIZED)); + console.error('VERIFY', error); + return callback(lang.UNAUTHORIZED); } else { return callback(null, generatePolicy(decoded, 'Allow', event.methodArn)); } }); } catch (error) { console.error('EXCEPTION', error); - return callback(new Error(lang.UNAUTHORIZED)); + return callback(lang.ERROR); } } }); } -const decodeToken = (token: string, callback: Callback) => { +export const decodeToken = (token: string, callback: Callback) => { let decode; try { @@ -53,17 +54,18 @@ const decodeToken = (token: string, callback: Callback) => { complete: true }); } catch (err) { - return callback(new Error(lang.UNPROCESSABLE)); + console.error('DECODE', err); + return callback(lang.ERROR); } finally { if (!decode) { - return callback(new Error(lang.UNAUTHORIZED)); + return callback(lang.UNAUTHORIZED); } else { return decode; } } } -const generatePolicy = (decoded: any, effect: string, resource: string): Authorizer => { +export const generatePolicy = (decoded: any, effect: string, resource: string): Authorizer => { const response: Authorizer = { principalId: decoded.sub }; if (effect && resource) { @@ -86,17 +88,17 @@ const generatePolicy = (decoded: any, effect: string, resource: string): Authori return response } -const getSigningKey = (key: any): string => (key.publicKey || key.rsaPublicKey); +export const getSigningKey = (key: any): string => (key.publicKey || key.rsaPublicKey); -const stripTokenFromHeader = (event:any, callback: Callback) => { +export const stripTokenFromHeader = (event:any, callback: Callback) => { if (!event.authorizationToken) { - return callback(new Error(lang.BAD_REQUEST)); + return callback(lang.UNAUTHORIZED); } const authToken = event.authorizationToken.split(' ')[1]; if (!authToken) { - return callback(new Error(lang.UNAUTHORIZED)); + return callback(lang.UNAUTHORIZED); } else { return authToken; } diff --git a/src/helpers/i18n/authorizer.ts b/src/helpers/i18n/authorizer.ts deleted file mode 100644 index 8c304ca..0000000 --- a/src/helpers/i18n/authorizer.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const BAD_REQUEST = '[400] bad request'; -export const INTERNAL_SERVER_ERROR = '[500] internal server error'; -export const UNAUTHORIZED = '[401] unauthorized'; -export const UNPROCESSABLE = '[422] unprocessable entity'; \ No newline at end of file diff --git a/src/helpers/interfaces/index.ts b/src/helpers/interfaces/all.ts similarity index 100% rename from src/helpers/interfaces/index.ts rename to src/helpers/interfaces/all.ts diff --git a/src/helpers/types/router/index.ts b/src/helpers/types/router.ts similarity index 100% rename from src/helpers/types/router/index.ts rename to src/helpers/types/router.ts diff --git a/src/i18n/authorizer.ts b/src/i18n/authorizer.ts new file mode 100644 index 0000000..66c6739 --- /dev/null +++ b/src/i18n/authorizer.ts @@ -0,0 +1,4 @@ +export enum Responses { + ERROR = 'Error: Invalid token', + UNAUTHORIZED = 'Unauthorized' +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 55b8151..fc6bf1a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,9 @@ "baseUrl": ".", "paths": { "@authorizers/*": ["src/authorizers/*"], - "@helpers/*": ["src/helpers/*"], + "@helpers/interfaces/*": ["src/helpers/interfaces/*"], + "@helpers/types/*": ["src/helpers/types/*"], + "@i18n/*": ["src/i18n/*"], "@routes/*": ["src/routes/*"], "@services/*": ["src/services/*"] } diff --git a/wallaby.js b/wallaby.js index bbbdb7f..6297c8d 100644 --- a/wallaby.js +++ b/wallaby.js @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ + module.exports = w => { return { compilers: { @@ -13,7 +15,8 @@ module.exports = w => { files: [ 'tsconfig.json', 'src/authorizers/*.ts', - 'src/helpers/*.ts', + 'src/helpers/*/*.ts', + 'src/i18n/*.ts', 'src/routes/*.ts', 'src/services/*.ts', ], diff --git a/webpack.config.js b/webpack.config.js index 2c6ef76..8f6d11a 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -16,6 +16,7 @@ module.exports = { alias: { '@authorizers': path.resolve(__dirname, 'src', 'authorizers'), '@helpers': path.resolve(__dirname, 'src', 'helpers'), + '@i18n': path.resolve(__dirname, 'src', 'i18n'), '@routes': path.resolve(__dirname, 'src', 'routes'), '@services': path.resolve(__dirname, 'src', 'services') },