Skip to content

Commit

Permalink
refactor(types): lambda service uses aws-lambda events
Browse files Browse the repository at this point in the history
  • Loading branch information
jagregory committed Dec 7, 2021
1 parent 402588d commit 87833e2
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 67 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@jest/globals": "^27.0.6",
"@semantic-release/changelog": "^5.0.1",
"@semantic-release/git": "^9.0.0",
"@types/aws-lambda": "^8.10.48",
"@types/aws-lambda": "^8.10.85",
"@types/body-parser": "^1.19.0",
"@types/cors": "^2.8.6",
"@types/express": "^4.17.13",
Expand All @@ -37,6 +37,7 @@
"@types/lodash.mergewith": "^4.6.6",
"@types/supertest": "^2.0.11",
"@types/uuid": "^8.3.3",
"@types/node": "^16.11.11",
"@typescript-eslint/eslint-plugin": "^2.27.0",
"@typescript-eslint/parser": "^2.27.0",
"esbuild": "^0.12.15",
Expand Down
86 changes: 76 additions & 10 deletions src/services/lambda.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ describe("Lambda function invoker", () => {
FunctionName: "MyLambdaName",
InvocationType: "RequestResponse",
Payload: expect.jsonMatching({
version: 0,
version: "0",
callerContext: { awsSdkVersion: version, clientId: "clientId" },
region: "local",
userPoolId: "userPoolId",
Expand All @@ -225,7 +225,11 @@ describe("Lambda function invoker", () => {
validation: "data",
},
},
response: {},
response: {
autoConfirmUser: false,
autoVerifyEmail: false,
autoVerifyPhone: false,
},
userName: "username",
}),
});
Expand Down Expand Up @@ -267,7 +271,7 @@ describe("Lambda function invoker", () => {
FunctionName: "MyLambdaName",
InvocationType: "RequestResponse",
Payload: expect.jsonMatching({
version: 0,
version: "0",
callerContext: { awsSdkVersion: version, clientId: "clientId" },
region: "local",
userPoolId: "userPoolId",
Expand All @@ -276,13 +280,15 @@ describe("Lambda function invoker", () => {
clientMetadata: {
client: "metadata",
},
userAttributes: {},
password: "password",
validationData: {
validation: "data",
},
},
response: {},
response: {
desiredDeliveryMediums: [],
userAttributes: {},
},
userName: "username",
}),
});
Expand All @@ -292,8 +298,6 @@ describe("Lambda function invoker", () => {
describe.each`
trigger | source
${"PostAuthentication"} | ${"PostAuthentication_Authentication"}
${"PostConfirmation"} | ${"PostConfirmation_ConfirmSignUp"}
${"PostConfirmation"} | ${"PostConfirmation_ConfirmForgotPassword"}
`("$source", ({ trigger, source }) => {
it("invokes the lambda", async () => {
const response = Promise.resolve({
Expand Down Expand Up @@ -327,7 +331,65 @@ describe("Lambda function invoker", () => {
FunctionName: "MyLambdaName",
InvocationType: "RequestResponse",
Payload: expect.jsonMatching({
version: 0,
version: "0",
callerContext: { awsSdkVersion: version, clientId: "clientId" },
region: "local",
userPoolId: "userPoolId",
triggerSource: source,
request: {
userAttributes: {
user: "attributes",
},
clientMetadata: {
client: "metadata",
},
newDeviceUsed: false,
},
response: {},
userName: "username",
}),
});
});
});

describe.each`
trigger | source
${"PostConfirmation"} | ${"PostConfirmation_ConfirmSignUp"}
${"PostConfirmation"} | ${"PostConfirmation_ConfirmForgotPassword"}
`("$source", ({ trigger, source }) => {
it("invokes the lambda", async () => {
const response = Promise.resolve({
StatusCode: 200,
Payload: '{ "some": "json" }',
});
mockLambdaClient.invoke.mockReturnValue({
promise: () => response,
} as any);
const lambda = new LambdaService(
{
[trigger]: "MyLambdaName",
},
mockLambdaClient
);

await lambda.invoke(TestContext, trigger, {
clientId: "clientId",
triggerSource: source,
username: "username",
userPoolId: "userPoolId",
userAttributes: {
user: "attributes",
},
clientMetadata: {
client: "metadata",
},
});

expect(mockLambdaClient.invoke).toHaveBeenCalledWith({
FunctionName: "MyLambdaName",
InvocationType: "RequestResponse",
Payload: expect.jsonMatching({
version: "0",
callerContext: { awsSdkVersion: version, clientId: "clientId" },
region: "local",
userPoolId: "userPoolId",
Expand Down Expand Up @@ -388,7 +450,7 @@ describe("Lambda function invoker", () => {
FunctionName: "MyLambdaName",
InvocationType: "RequestResponse",
Payload: expect.jsonMatching({
version: 0,
version: "0",
callerContext: { awsSdkVersion: version, clientId: "clientId" },
region: "local",
userPoolId: "userPoolId",
Expand All @@ -402,7 +464,11 @@ describe("Lambda function invoker", () => {
client: "metadata",
},
},
response: {},
response: {
smsMessage: "",
emailMessage: "",
emailSubject: "",
},
}),
});
});
Expand Down
208 changes: 156 additions & 52 deletions src/services/lambda.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import { CognitoUserPoolEvent } from "aws-lambda";
import {
CreateAuthChallengeTriggerEvent,
CustomEmailSenderTriggerEvent,
CustomMessageTriggerEvent,
DefineAuthChallengeTriggerEvent,
PostAuthenticationTriggerEvent,
PostConfirmationTriggerEvent,
PreAuthenticationTriggerEvent,
PreSignUpTriggerEvent,
UserMigrationTriggerEvent,
VerifyAuthChallengeResponseTriggerEvent,
} from "aws-lambda";
import type { Lambda as LambdaClient } from "aws-sdk";
import { InvocationResponse } from "aws-sdk/clients/lambda";
import { version as awsSdkVersion } from "aws-sdk/package.json";
import {
InvalidLambdaResponseError,
UnexpectedLambdaExceptionError,
UserLambdaValidationError,
} from "../errors";
import { version as awsSdkVersion } from "aws-sdk/package.json";
import { Context } from "./context";

type CognitoUserPoolEvent =
| CreateAuthChallengeTriggerEvent
| CustomEmailSenderTriggerEvent
| CustomMessageTriggerEvent
| DefineAuthChallengeTriggerEvent
| PostAuthenticationTriggerEvent
| PostConfirmationTriggerEvent
| PreAuthenticationTriggerEvent
| PreSignUpTriggerEvent
| UserMigrationTriggerEvent
| VerifyAuthChallengeResponseTriggerEvent;

interface EventCommonParameters {
clientId: string;
userAttributes: Record<string, string>;
Expand Down Expand Up @@ -125,56 +148,7 @@ export class LambdaService implements Lambda {
throw new Error(`${trigger} trigger not configured`);
}

const lambdaEvent: CognitoUserPoolEvent = {
version: 0, // TODO: how do we know what this is?
callerContext: {
awsSdkVersion,
clientId: event.clientId,
},
region: "local", // TODO: pull from above,
userPoolId: event.userPoolId,
triggerSource: event.triggerSource,
userName: event.username,
request: {
userAttributes: event.userAttributes,
},
response: {},
};

switch (event.triggerSource) {
case "PostAuthentication_Authentication":
case "PostConfirmation_ConfirmForgotPassword":
case "PostConfirmation_ConfirmSignUp": {
lambdaEvent.request.clientMetadata = event.clientMetadata;
break;
}
case "PreSignUp_AdminCreateUser":
case "PreSignUp_ExternalProvider":
case "PreSignUp_SignUp": {
lambdaEvent.request.clientMetadata = event.clientMetadata;
lambdaEvent.request.validationData = event.validationData;
break;
}
case "UserMigration_Authentication": {
lambdaEvent.request.clientMetadata = event.clientMetadata;
lambdaEvent.request.password = event.password;
lambdaEvent.request.validationData = event.validationData;

break;
}
case "CustomMessage_SignUp":
case "CustomMessage_AdminCreateUser":
case "CustomMessage_ResendCode":
case "CustomMessage_ForgotPassword":
case "CustomMessage_UpdateUserAttribute":
case "CustomMessage_VerifyUserAttribute":
case "CustomMessage_Authentication": {
lambdaEvent.request.clientMetadata = event.clientMetadata;
lambdaEvent.request.codeParameter = event.codeParameter;
lambdaEvent.request.usernameParameter = event.usernameParameter;
break;
}
}
const lambdaEvent = this.createLambdaEvent(event);

ctx.logger.debug(
{
Expand Down Expand Up @@ -214,4 +188,134 @@ export class LambdaService implements Lambda {
throw new UserLambdaValidationError(result.FunctionError);
}
}

private createLambdaEvent(
event:
| CustomMessageEvent
| PostAuthenticationEvent
| PostConfirmationEvent
| PreSignUpEvent
| UserMigrationEvent
): CognitoUserPoolEvent {
const version = "0"; // TODO: how do we know what this is?
const callerContext = {
awsSdkVersion,
clientId: event.clientId,
};
const region = "local"; // TODO: pull from above,

switch (event.triggerSource) {
case "PostAuthentication_Authentication": {
return {
version,
callerContext,
region,
userPoolId: event.userPoolId,
triggerSource: event.triggerSource,
userName: event.username,
request: {
userAttributes: event.userAttributes,
clientMetadata: event.clientMetadata,
newDeviceUsed: false,
},
response: {},
};
}

case "PostConfirmation_ConfirmForgotPassword":
case "PostConfirmation_ConfirmSignUp": {
return {
version,
callerContext,
region,
userPoolId: event.userPoolId,
triggerSource: event.triggerSource,
userName: event.username,
request: {
userAttributes: event.userAttributes,
clientMetadata: event.clientMetadata,
},
response: {},
};
}

case "PreSignUp_AdminCreateUser":
case "PreSignUp_ExternalProvider":
case "PreSignUp_SignUp": {
return {
version,
callerContext,
region,
userPoolId: event.userPoolId,
triggerSource: event.triggerSource,
userName: event.username,
request: {
userAttributes: event.userAttributes,
clientMetadata: event.clientMetadata,
validationData: event.validationData,
},
response: {
autoConfirmUser: false,
autoVerifyEmail: false,
autoVerifyPhone: false,
},
};
}

case "UserMigration_Authentication": {
return {
version,
callerContext,
region,
userPoolId: event.userPoolId,
triggerSource: event.triggerSource,
userName: event.username,
request: {
clientMetadata: event.clientMetadata,
password: event.password,
validationData: event.validationData,
},
response: {
desiredDeliveryMediums: [],
finalUserStatus: undefined,
forceAliasCreation: undefined,
messageAction: undefined,
userAttributes: {},
},
};
}

case "CustomMessage_SignUp":
case "CustomMessage_AdminCreateUser":
case "CustomMessage_ResendCode":
case "CustomMessage_ForgotPassword":
case "CustomMessage_UpdateUserAttribute":
case "CustomMessage_VerifyUserAttribute":
case "CustomMessage_Authentication": {
return {
version,
callerContext,
region,
userPoolId: event.userPoolId,
triggerSource: event.triggerSource,
userName: event.username,
request: {
clientMetadata: event.clientMetadata,
codeParameter: event.codeParameter,
usernameParameter: event.usernameParameter,
userAttributes: {},
},
response: {
smsMessage: "",
emailMessage: "",
emailSubject: "",
},
};
}

default: {
throw new Error("Unsupported Trigger Source");
}
}
}
}
Loading

0 comments on commit 87833e2

Please sign in to comment.