diff --git a/packages/@aws-cdk/aws-cognito/README.md b/packages/@aws-cdk/aws-cognito/README.md index f01f8646a4d1f..f11f9d7ebb294 100644 --- a/packages/@aws-cdk/aws-cognito/README.md +++ b/packages/@aws-cdk/aws-cognito/README.md @@ -431,6 +431,18 @@ new cognito.UserPool(this, 'myuserpool', { }); ``` +If `fromName` does not comply RFC 5322 atom or quoted-string, it will be quoted or mime-encoded. + +```ts +new cognito.UserPool(this, 'myuserpool', { + email: cognito.UserPoolEmail.withSES({ + fromEmail: 'noreply@myawesomeapp.com', + fromName: 'myname@mycompany.com', + }), +}); +// => From: "myname@mycompany.com" +``` + ### Device Tracking User pools can be configured to track devices that users have logged in to. diff --git a/packages/@aws-cdk/aws-cognito/lib/user-pool-email.ts b/packages/@aws-cdk/aws-cognito/lib/user-pool-email.ts index 27eb3f8c240d3..d275c4d3a5dd2 100644 --- a/packages/@aws-cdk/aws-cognito/lib/user-pool-email.ts +++ b/packages/@aws-cdk/aws-cognito/lib/user-pool-email.ts @@ -164,9 +164,10 @@ class SESEmail extends UserPoolEmail { throw new Error('Your stack region cannot be determined so "sesRegion" is required in SESOptions'); } - let from = this.options.fromEmail; + let from = encodeAndTest(this.options.fromEmail); if (this.options.fromName) { - from = `${this.options.fromName} <${this.options.fromEmail}>`; + const fromName = formatFromName(this.options.fromName); + from = `${fromName} <${from}>`; } if (this.options.sesVerifiedDomain) { @@ -177,7 +178,7 @@ class SESEmail extends UserPoolEmail { } return { - from: encodeAndTest(from), + from, replyToEmailAddress: encodeAndTest(this.options.replyTo), configurationSet: this.options.configurationSetName, emailSendingAccount: 'DEVELOPER', @@ -202,3 +203,59 @@ function encodeAndTest(input: string | undefined): string | undefined { return undefined; } } + +/** + * Formats `fromName` to comply RFC 5322 + * + * @see https://www.rfc-editor.org/rfc/rfc5322#section-3.4 + */ +function formatFromName(fromName: string): string { + // mime encode for non US-ASCII characters + // see RFC 2047 for details https://www.rfc-editor.org/rfc/rfc2047 + if (!isAscii(fromName)) { + const base64Name = Buffer.from(fromName, 'utf-8').toString('base64'); + return `=?UTF-8?B?${base64Name}?=`; + } + + // makes a quoted-string unless fromName is a phrase (only atext and space) + // or a quoted-string already + if (!(isSimplePhrase(fromName) || isQuotedString(fromName))) { + // in quoted-string, `\` and `"` should be escaped by `\` + // e.g. `"foo \"bar\" \\baz"` + const quotedName = fromName.replace(/[\\"]/g, (ch) => `\\${ch}`); + return `"${quotedName}"`; + } + + // otherwise, returns as is + return fromName; +} + +/** + * Returns whether the input is a printable US-ASCII string + */ +function isAscii(input: string): boolean { + // U+0020 (space) - U+007E (`~`) + return /^[\u0020-\u007E]+$/u.test(input); +} + +/** + * Returns whether the input is a phrase excluding quoted-string + * + * @see https://www.rfc-editor.org/rfc/rfc5322#section-3.2 + */ +function isSimplePhrase(input: string): boolean { + return /^[\w !#$%&'*+-\/=?^_`{|}~]+$/.test(input); +} + +/** + * Returns whether the input is already a quoted-string + * + * @see https://www.rfc-editor.org/rfc/rfc5322#section-3.2.4 + */ +function isQuotedString(input: string): boolean { + // in quoted-string, `\` and `"` should be esacaped by `\` + // + // match: `"foo.bar"` / `"foo \"bar\""` / `"foo \\ bar"` + // not match: `"bare " dquote"` / `"unclosed escape \"` / `"unclosed dquote` + return /^"(?:[^\\"]|\\.)*"$/.test(input); +} diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json new file mode 100644 index 0000000000000..ab8ca0bd4a1f2 --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "IntegTestDefaultTestDeployAssertE3E7D2A4.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.template.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/IntegTestDefaultTestDeployAssertE3E7D2A4.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/cdk.out b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/cdk.out index 588d7b269d34f..145739f539580 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"20.0.0"} \ No newline at end of file +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-pool-signup-code.assets.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-ses-email.assets.json similarity index 61% rename from packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-pool-signup-code.assets.json rename to packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-ses-email.assets.json index ecc9fe25929b4..f41ed844f36e1 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-pool-signup-code.assets.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-ses-email.assets.json @@ -1,15 +1,15 @@ { - "version": "20.0.0", + "version": "22.0.0", "files": { - "3294a2beef1e4a711276251bf311cdf22b70152f30241f0d155898e2ab9ad091": { + "55384e618066ba251d0576ca224e2109d90f1e97e067d2d9bfb1476d43fff838": { "source": { - "path": "integ-user-pool-signup-code.template.json", + "path": "integ-user-ses-email.template.json", "packaging": "file" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "3294a2beef1e4a711276251bf311cdf22b70152f30241f0d155898e2ab9ad091.json", + "objectKey": "55384e618066ba251d0576ca224e2109d90f1e97e067d2d9bfb1476d43fff838.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-pool-signup-code.template.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-ses-email.template.json similarity index 97% rename from packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-pool-signup-code.template.json rename to packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-ses-email.template.json index 76d04227ceaed..06d48aad9d5dd 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-pool-signup-code.template.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ-user-ses-email.template.json @@ -20,7 +20,7 @@ }, "EmailConfiguration": { "EmailSendingAccount": "DEVELOPER", - "From": "noreply@example.com", + "From": "\"myname@mycompany.com\" ", "ReplyToEmailAddress": "support@example.com", "SourceArn": { "Fn::Join": [ diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ.json index b0fa49a1c72f9..7719605f8486c 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/integ.json @@ -1,14 +1,12 @@ { - "version": "20.0.0", + "version": "22.0.0", "testCases": { - "integ.user-pool-ses-email": { + "IntegTest/DefaultTest": { "stacks": [ - "integ-user-pool-signup-code" + "integ-user-ses-email" ], - "diffAssets": false, - "stackUpdateWorkflow": true + "assertionStack": "IntegTest/DefaultTest/DeployAssert", + "assertionStackName": "IntegTestDefaultTestDeployAssertE3E7D2A4" } - }, - "synthContext": {}, - "enableLookups": false + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/manifest.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/manifest.json index d04a7ad4df06b..4f837b695cd65 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/manifest.json @@ -1,33 +1,27 @@ { - "version": "20.0.0", + "version": "22.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, - "integ-user-pool-signup-code.assets": { + "integ-user-ses-email.assets": { "type": "cdk:asset-manifest", "properties": { - "file": "integ-user-pool-signup-code.assets.json", + "file": "integ-user-ses-email.assets.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" } }, - "integ-user-pool-signup-code": { + "integ-user-ses-email": { "type": "aws:cloudformation:stack", "environment": "aws://unknown-account/unknown-region", "properties": { - "templateFile": "integ-user-pool-signup-code.template.json", + "templateFile": "integ-user-ses-email.template.json", "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/3294a2beef1e4a711276251bf311cdf22b70152f30241f0d155898e2ab9ad091.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/55384e618066ba251d0576ca224e2109d90f1e97e067d2d9bfb1476d43fff838.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ - "integ-user-pool-signup-code.assets" + "integ-user-ses-email.assets" ], "lookupRole": { "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", @@ -36,35 +30,88 @@ } }, "dependencies": [ - "integ-user-pool-signup-code.assets" + "integ-user-ses-email.assets" ], "metadata": { - "/integ-user-pool-signup-code/myuserpool/Resource": [ + "/integ-user-ses-email/myuserpool/Resource": [ { "type": "aws:cdk:logicalId", "data": "myuserpool01998219" } ], - "/integ-user-pool-signup-code/user-pool-id": [ + "/integ-user-ses-email/user-pool-id": [ { "type": "aws:cdk:logicalId", "data": "userpoolid" } ], - "/integ-user-pool-signup-code/BootstrapVersion": [ + "/integ-user-ses-email/BootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "BootstrapVersion" } ], - "/integ-user-pool-signup-code/CheckBootstrapVersion": [ + "/integ-user-ses-email/CheckBootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } ] }, - "displayName": "integ-user-pool-signup-code" + "displayName": "integ-user-ses-email" + }, + "IntegTestDefaultTestDeployAssertE3E7D2A4.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "IntegTestDefaultTestDeployAssertE3E7D2A4.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "IntegTestDefaultTestDeployAssertE3E7D2A4": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "IntegTestDefaultTestDeployAssertE3E7D2A4.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "IntegTestDefaultTestDeployAssertE3E7D2A4.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "IntegTestDefaultTestDeployAssertE3E7D2A4.assets" + ], + "metadata": { + "/IntegTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/IntegTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "IntegTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/tree.json b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/tree.json index fb6d64ba764b1..df43736a6cf7d 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.js.snapshot/tree.json @@ -4,25 +4,17 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" - } - }, - "integ-user-pool-signup-code": { - "id": "integ-user-pool-signup-code", - "path": "integ-user-pool-signup-code", + "integ-user-ses-email": { + "id": "integ-user-ses-email", + "path": "integ-user-ses-email", "children": { "myuserpool": { "id": "myuserpool", - "path": "integ-user-pool-signup-code/myuserpool", + "path": "integ-user-ses-email/myuserpool", "children": { "Resource": { "id": "Resource", - "path": "integ-user-pool-signup-code/myuserpool/Resource", + "path": "integ-user-ses-email/myuserpool/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::Cognito::UserPool", "aws:cdk:cloudformation:props": { @@ -42,7 +34,7 @@ "allowAdminCreateUserOnly": true }, "emailConfiguration": { - "from": "noreply@example.com", + "from": "\"myname@mycompany.com\" ", "replyToEmailAddress": "support@example.com", "emailSendingAccount": "DEVELOPER", "sourceArn": { @@ -87,22 +79,100 @@ }, "user-pool-id": { "id": "user-pool-id", - "path": "integ-user-pool-signup-code/user-pool-id", + "path": "integ-user-ses-email/user-pool-id", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-user-ses-email/BootstrapVersion", "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-user-ses-email/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" } } }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "IntegTest": { + "id": "IntegTest", + "path": "IntegTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "IntegTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "IntegTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.168" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "IntegTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "IntegTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "IntegTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.168" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.ts b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.ts index 8278649d12f7f..d4064158ff784 100644 --- a/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.ts +++ b/packages/@aws-cdk/aws-cognito/test/integ.user-pool-ses-email.ts @@ -1,9 +1,9 @@ import { App, CfnOutput, RemovalPolicy, Stack } from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; import { UserPool, UserPoolEmail } from '../lib'; - const app = new App(); -const stack = new Stack(app, 'integ-user-pool-signup-code'); +const stack = new Stack(app, 'integ-user-ses-email'); const userpool = new UserPool(stack, 'myuserpool', { removalPolicy: RemovalPolicy.DESTROY, @@ -11,6 +11,7 @@ const userpool = new UserPool(stack, 'myuserpool', { email: UserPoolEmail.withSES({ sesRegion: 'us-east-1', fromEmail: 'noreply@example.com', + fromName: 'myname@mycompany.com', replyTo: 'support@example.com', sesVerifiedDomain: 'example.com', }), @@ -20,4 +21,4 @@ new CfnOutput(stack, 'user-pool-id', { value: userpool.userPoolId, }); -app.synth(); +new IntegTest(app, 'IntegTest', { testCases: [stack] }); diff --git a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts index 9cc1cfc5fb4a8..edec04ad26fb5 100644 --- a/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts +++ b/packages/@aws-cdk/aws-cognito/test/user-pool.test.ts @@ -1708,7 +1708,158 @@ describe('User Pool', () => { }, }, }); + }); + + test('email withSES with name as quoted-string', () => { + // GIVEN + const stack = new Stack(undefined, undefined, { + env: { + region: 'us-east-1', + account: '11111111111', + }, + }); + + // WHEN + new UserPool(stack, 'Pool', { + email: UserPoolEmail.withSES({ + fromEmail: 'mycustomemail@example.com', + fromName: '"My Custom Email"', + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + EmailConfiguration: { + EmailSendingAccount: 'DEVELOPER', + From: '"My Custom Email" ', + SourceArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ses:us-east-1:11111111111:identity/mycustomemail@example.com', + ], + ], + }, + }, + }); + }); + + test('email withSES with name with non atom characters', () => { + // GIVEN + const stack = new Stack(undefined, undefined, { + env: { + region: 'us-east-1', + account: '11111111111', + }, + }); + // WHEN + new UserPool(stack, 'Pool', { + email: UserPoolEmail.withSES({ + fromEmail: 'mycustomemail@example.com', + fromName: 'mycustomname@example.com', + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + EmailConfiguration: { + EmailSendingAccount: 'DEVELOPER', + From: '"mycustomname@example.com" ', + SourceArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ses:us-east-1:11111111111:identity/mycustomemail@example.com', + ], + ], + }, + }, + }); + }); + + test('email withSES with name with quotes', () => { + // GIVEN + const stack = new Stack(undefined, undefined, { + env: { + region: 'us-east-1', + account: '11111111111', + }, + }); + + // WHEN + new UserPool(stack, 'Pool', { + email: UserPoolEmail.withSES({ + fromEmail: 'mycustomemail@example.com', + fromName: 'Foo "Bar" \\Baz', + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + EmailConfiguration: { + EmailSendingAccount: 'DEVELOPER', + From: '"Foo \\"Bar\\" \\\\Baz" ', + SourceArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ses:us-east-1:11111111111:identity/mycustomemail@example.com', + ], + ], + }, + }, + }); + }); + + test('email withSES with name with non US-ASCII characters', () => { + // GIVEN + const stack = new Stack(undefined, undefined, { + env: { + region: 'us-east-1', + account: '11111111111', + }, + }); + + // WHEN + new UserPool(stack, 'Pool', { + email: UserPoolEmail.withSES({ + fromEmail: 'mycustomemail@example.com', + fromName: 'あいう', + }), + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Cognito::UserPool', { + EmailConfiguration: { + EmailSendingAccount: 'DEVELOPER', + From: '=?UTF-8?B?44GC44GE44GG?= ', + SourceArn: { + 'Fn::Join': [ + '', + [ + 'arn:', + { + Ref: 'AWS::Partition', + }, + ':ses:us-east-1:11111111111:identity/mycustomemail@example.com', + ], + ], + }, + }, + }); }); test('email withSES with valid region', () => {