@aws/nx-plugin 0.1.6 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/LICENSE-THIRD-PARTY +1554 -3241
  2. package/generators.json +1 -13
  3. package/package.json +14 -14
  4. package/src/cloudscape-website/app/README.md +84 -48
  5. package/src/cloudscape-website/app/__snapshots__/generator.spec.ts.snap +168 -233
  6. package/src/cloudscape-website/app/files/app/README.md.template +44 -0
  7. package/src/cloudscape-website/app/files/app/src/layouts/App/index.tsx.template +40 -43
  8. package/src/cloudscape-website/app/files/app/src/layouts/App/navitems.ts.template +3 -3
  9. package/src/cloudscape-website/app/files/app/src/layouts/Routes/index.tsx.template +4 -6
  10. package/src/cloudscape-website/app/files/app/src/main.tsx.template +7 -10
  11. package/src/cloudscape-website/app/files/app/src/pages/Home/index.tsx.template +0 -2
  12. package/src/cloudscape-website/app/files/common/constructs/src/app/static-websites/__websiteNameKebabCase__.ts.template +13 -0
  13. package/src/cloudscape-website/app/files/common/constructs/src/{__websiteNameKebabCase__ → core}/static-website.ts.template +79 -144
  14. package/src/cloudscape-website/app/generator.js +90 -74
  15. package/src/cloudscape-website/app/generator.js.map +1 -1
  16. package/src/cloudscape-website/app/schema.d.ts +3 -5
  17. package/src/cloudscape-website/app/schema.json +1 -24
  18. package/src/cloudscape-website/cognito-auth/README.md +53 -32
  19. package/src/cloudscape-website/cognito-auth/__snapshots__/generator.spec.ts.snap +162 -124
  20. package/src/cloudscape-website/cognito-auth/files/app/components/CognitoAuth/index.tsx.template +53 -39
  21. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/core/user-identity.ts.template +168 -0
  22. package/src/cloudscape-website/cognito-auth/generator.js +130 -47
  23. package/src/cloudscape-website/cognito-auth/generator.js.map +1 -1
  24. package/src/cloudscape-website/cognito-auth/schema.d.ts +1 -0
  25. package/src/cloudscape-website/cognito-auth/schema.json +7 -1
  26. package/src/cloudscape-website/runtime-config/__snapshots__/generator.spec.ts.snap +20 -15
  27. package/src/cloudscape-website/runtime-config/files/app/components/RuntimeConfig/index.tsx.template +7 -10
  28. package/src/cloudscape-website/runtime-config/files/app/hooks/useRuntimeConfig.tsx.template +13 -0
  29. package/src/cloudscape-website/runtime-config/generator.js +4 -2
  30. package/src/cloudscape-website/runtime-config/generator.js.map +1 -1
  31. package/src/infra/app/README.md +71 -46
  32. package/src/infra/app/__snapshots__/generator.spec.ts.snap +184 -305
  33. package/src/infra/app/files/app/README.md.template +76 -0
  34. package/src/infra/app/files/app/src/main.ts.template +18 -0
  35. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/aws-prototyping.guard +1282 -0
  36. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/cfn-nag.guard +6839 -0
  37. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/hipaa-security.guard +2807 -0
  38. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/nist-csf.guard +2585 -0
  39. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/pci-dss-3-2-1.guard +2236 -0
  40. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-reliability-pillar.guard +885 -0
  41. package/src/infra/app/files/common/constructs/src/core/cfn-guard-rules/wa-security-pillar.guard +2205 -0
  42. package/src/infra/app/files/common/constructs/src/core/cfn-guard.ts.template +63 -0
  43. package/src/infra/app/generator.js +36 -7
  44. package/src/infra/app/generator.js.map +1 -1
  45. package/src/infra/app/schema.d.ts +10 -1
  46. package/src/infra/app/schema.json +16 -8
  47. package/src/trpc/backend/README.md +102 -80
  48. package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +42 -19
  49. package/src/trpc/backend/files/backend/README.md.template +33 -0
  50. package/src/trpc/backend/files/common/constructs/src/app/trpc-apis/__apiNameKebabCase__.ts.template +18 -0
  51. package/src/trpc/backend/files/common/constructs/src/{__apiNameKebabCase__/index.ts.template → core/trpc-api.ts.template} +12 -16
  52. package/src/trpc/backend/files/schema/README.md.template +33 -0
  53. package/src/trpc/backend/generator.js +30 -44
  54. package/src/trpc/backend/generator.js.map +1 -1
  55. package/src/trpc/backend/schema.d.ts +3 -1
  56. package/src/trpc/backend/schema.json +8 -13
  57. package/src/trpc/react/README.md +46 -66
  58. package/src/trpc/react/__snapshots__/generator.spec.ts.snap +104 -65
  59. package/src/trpc/react/files/src/components/TrpcClients/IsolatedTrpcProvider.tsx.template +75 -0
  60. package/src/trpc/react/files/src/components/TrpcClients/TrpcApis.tsx.template +1 -0
  61. package/src/trpc/react/files/src/components/TrpcClients/TrpcClientProviders.tsx.template +10 -0
  62. package/src/trpc/react/files/src/components/TrpcClients/index.tsx.template +5 -0
  63. package/src/trpc/react/files/src/hooks/useSigV4.tsx.template +38 -0
  64. package/src/trpc/react/files/src/hooks/use__apiNameClassName__.tsx.template +3 -0
  65. package/src/trpc/react/generator.js +124 -25
  66. package/src/trpc/react/generator.js.map +1 -1
  67. package/src/trpc/react/schema.json +2 -2
  68. package/src/ts/lib/__snapshots__/generator.spec.ts.snap +47 -93
  69. package/src/ts/lib/eslint.d.ts +1 -2
  70. package/src/ts/lib/eslint.js +62 -21
  71. package/src/ts/lib/eslint.js.map +1 -1
  72. package/src/ts/lib/files/README.md.template +33 -0
  73. package/src/ts/lib/generator.js +44 -5
  74. package/src/ts/lib/generator.js.map +1 -1
  75. package/src/ts/lib/schema.d.ts +1 -4
  76. package/src/ts/lib/schema.json +2 -21
  77. package/src/ts/lib/ts-project-utils.js +3 -18
  78. package/src/ts/lib/ts-project-utils.js.map +1 -1
  79. package/src/ts/lib/vitest.js +12 -0
  80. package/src/ts/lib/vitest.js.map +1 -1
  81. package/src/utils/ast.d.ts +13 -0
  82. package/src/utils/ast.js +102 -0
  83. package/src/utils/ast.js.map +1 -0
  84. package/src/utils/files/common/constructs/src/app/index.ts.template +0 -0
  85. package/src/utils/files/common/constructs/src/{runtime-config → core}/runtime-config.ts.template +3 -5
  86. package/src/utils/files/common/constructs/src/index.ts.template +2 -1
  87. package/src/utils/files/common/readme/README.md.template +33 -0
  88. package/src/utils/files/common/types/src/runtime-config.ts.template +2 -13
  89. package/src/utils/format.d.ts +1 -1
  90. package/src/utils/format.js +2 -2
  91. package/src/utils/format.js.map +1 -1
  92. package/src/utils/names.d.ts +2 -0
  93. package/src/utils/names.js +27 -0
  94. package/src/utils/names.js.map +1 -0
  95. package/src/utils/npm-scope.js.map +1 -1
  96. package/src/utils/paths.js.map +1 -1
  97. package/src/utils/shared-constructs.js +37 -4
  98. package/src/utils/shared-constructs.js.map +1 -1
  99. package/src/utils/test.d.ts +2 -0
  100. package/src/utils/test.js +19 -0
  101. package/src/utils/test.js.map +1 -0
  102. package/src/utils/versions.d.ts +15 -9
  103. package/src/utils/versions.js +14 -8
  104. package/src/utils/versions.js.map +1 -1
  105. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/cloudfront-web-acl.ts.template +0 -317
  106. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/index.ts.template +0 -4
  107. package/src/cloudscape-website/app/files/common/constructs/src/__websiteNameKebabCase__/webacl_event_handler/index.ts.template +0 -301
  108. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/index.ts.template +0 -4
  109. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/user-identity.ts.template +0 -66
  110. package/src/cloudscape-website/cognito-auth/files/common/constructs/src/identity/userpool-with-mfa.ts.template +0 -70
  111. package/src/gitlab/generator.d.ts +0 -8
  112. package/src/gitlab/generator.js +0 -16
  113. package/src/gitlab/generator.js.map +0 -1
  114. package/src/gitlab/schema.d.ts +0 -9
  115. package/src/gitlab/schema.json +0 -52
  116. package/src/infra/app/files/src/main.ts.template +0 -37
  117. package/src/trpc/react/files/src/components/TRPCClientProvider/index.tsx.template +0 -34
  118. package/src/trpc/react/files/src/hooks/useTrpc.tsx.template +0 -5
  119. package/src/ts/cjs-to-esm/generator.d.ts +0 -12
  120. package/src/ts/cjs-to-esm/generator.js +0 -189
  121. package/src/ts/cjs-to-esm/generator.js.map +0 -1
  122. package/src/ts/cjs-to-esm/schema.d.ts +0 -9
  123. package/src/ts/cjs-to-esm/schema.json +0 -28
  124. /package/src/infra/app/files/{cdk.json → app/cdk.json} +0 -0
  125. /package/src/infra/app/files/{src → app/src}/stacks/application-stack.ts.template +0 -0
  126. /package/src/utils/files/common/constructs/src/{runtime-config → core}/index.ts.template +0 -0
@@ -1,12 +1,10 @@
1
1
  // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
2
 
3
3
  exports[`cognito-auth generator > should generate files > cognito-auth-component 1`] = `
4
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
5
- SPDX-License-Identifier: Apache-2.0 */
6
- import { CognitoAuth as NorthstarCognitoAuth } from '@aws-northstar/ui';
7
- import React, { useContext } from 'react';
8
- import Config from '../../config';
9
- import { RuntimeConfigContext } from '../RuntimeConfig';
4
+ "import React, { PropsWithChildren, useEffect } from 'react';
5
+ import { AuthProvider, AuthProviderProps, useAuth } from 'react-oidc-context';
6
+ import { Alert, Spinner } from '@cloudscape-design/components';
7
+ import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
10
8
 
11
9
  /**
12
10
  * Sets up the Cognito auth.
@@ -14,104 +12,119 @@ import { RuntimeConfigContext } from '../RuntimeConfig';
14
12
  * This assumes a runtime-config.json file is present at '/'. In order for Auth to be set up automatically,
15
13
  * the runtime-config.json must have the cognitoProps set.
16
14
  */
17
- const CognitoAuth: React.FC<any> = ({ children }) => {
18
- const runtimeConfig = useContext(RuntimeConfigContext);
19
-
20
- return runtimeConfig?.cognitoProps ? (
21
- <NorthstarCognitoAuth
22
- header={Config.applicationName}
23
- userPoolId={runtimeConfig.cognitoProps.userPoolId}
24
- clientId={runtimeConfig.cognitoProps.userPoolWebClientId}
25
- region={runtimeConfig.cognitoProps.region}
26
- identityPoolId={runtimeConfig.cognitoProps.identityPoolId}
27
- allowSignup={true}
28
- signUpAttributes={[
29
- {
30
- displayName: 'Email',
31
- name: 'email',
32
- required: true,
33
- },
34
- {
35
- displayName: 'Given name',
36
- name: 'given_name',
37
- required: true,
38
- },
39
- {
40
- displayName: 'Last name',
41
- name: 'family_name',
42
- required: true,
43
- },
44
- ]}
45
- >
46
- {children}
47
- </NorthstarCognitoAuth>
48
- ) : (
49
- <></>
15
+ const CognitoAuth: React.FC<PropsWithChildren> = ({ children }) => {
16
+ const { cognitoProps } = useRuntimeConfig();
17
+
18
+ if (!cognitoProps) {
19
+ return (
20
+ <Alert type="error" header="Runtime config configuration error">
21
+ The cognitoProps have not been configured in the runtime-config.json.
22
+ </Alert>
23
+ );
24
+ }
25
+
26
+ const cognitoAuthConfig: AuthProviderProps = {
27
+ authority: \`https://cognito-idp.\${cognitoProps.region}.amazonaws.com/\${cognitoProps.userPoolId}\`,
28
+ client_id: cognitoProps.userPoolWebClientId,
29
+ redirect_uri: window.location.origin,
30
+ response_type: 'code',
31
+ scope: 'email openid profile',
32
+ };
33
+
34
+ return (
35
+ <AuthProvider {...cognitoAuthConfig}>
36
+ <CognitoAuthInternal>{children}</CognitoAuthInternal>
37
+ </AuthProvider>
50
38
  );
51
39
  };
52
40
 
41
+ const CognitoAuthInternal: React.FC<PropsWithChildren> = ({ children }) => {
42
+ const auth = useAuth();
43
+
44
+ useEffect(() => {
45
+ if (!auth.isAuthenticated && !auth.isLoading) {
46
+ auth.signinRedirect();
47
+ }
48
+ }, [auth]);
49
+
50
+ if (auth.isAuthenticated) {
51
+ return children;
52
+ } else if (auth.error) {
53
+ return (
54
+ <Alert type="error" header="Configuration error">
55
+ Error contacting Cognito. Please check your runtime-config.json is
56
+ configured with the correct endpoints.
57
+ </Alert>
58
+ );
59
+ } else {
60
+ return <Spinner />;
61
+ }
62
+ };
63
+
53
64
  export default CognitoAuth;
54
65
  "
55
66
  `;
56
67
 
57
68
  exports[`cognito-auth generator > should generate files > identity-index 1`] = `
58
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
59
- SPDX-License-Identifier: Apache-2.0 */
60
- export * from './user-identity.js';
61
- export * from './userpool-with-mfa.js';
69
+ "export * from './user-identity.js';
70
+ export * from './runtime-config.js';
62
71
  "
63
72
  `;
64
73
 
65
74
  exports[`cognito-auth generator > should generate files > user-identity 1`] = `
66
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
67
- SPDX-License-Identifier: Apache-2.0 */
68
- import {
75
+ "import {
69
76
  IdentityPool,
70
77
  UserPoolAuthenticationProvider,
71
78
  } from '@aws-cdk/aws-cognito-identitypool-alpha';
72
- import { CfnOutput, Stack } from 'aws-cdk-lib';
73
- import { UserPool, UserPoolClient } from 'aws-cdk-lib/aws-cognito';
79
+ import { CfnOutput, Duration, Lazy, Stack } from 'aws-cdk-lib';
80
+ import {
81
+ AccountRecovery,
82
+ CfnManagedLoginBranding,
83
+ CfnUserPoolDomain,
84
+ FeaturePlan,
85
+ Mfa,
86
+ OAuthScope,
87
+ UserPool,
88
+ UserPoolClient,
89
+ } from 'aws-cdk-lib/aws-cognito';
74
90
  import { Construct } from 'constructs';
75
- import { UserPoolWithMfa } from './userpool-with-mfa.js';
76
- import { RuntimeConfig } from '../runtime-config/index.js';
91
+ import { RuntimeConfig } from './runtime-config.js';
92
+ import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
77
93
 
78
94
  const WEB_CLIENT_ID = 'WebClient';
79
-
80
95
  /**
81
96
  * Creates a UserPool and Identity Pool with sane defaults configured intended for usage from a web client.
82
97
  */
83
98
  export class UserIdentity extends Construct {
99
+ public readonly region: string;
84
100
  public readonly identityPool: IdentityPool;
85
101
  public readonly userPool: UserPool;
86
102
  public readonly userPoolClient: UserPoolClient;
103
+ public readonly userPoolDomain: CfnUserPoolDomain;
87
104
 
88
105
  constructor(scope: Construct, id: string) {
89
106
  super(scope, id);
90
107
 
91
- // Unless explicitly stated, created a default Cognito User Pool and Web Client.
92
- this.userPool = new UserPoolWithMfa(this, 'UserPool');
93
-
94
- this.identityPool = new IdentityPool(this, 'IdentityPool');
95
-
96
- const existingClient = this.userPool.node.children.find(
97
- (e) => e.node.id === WEB_CLIENT_ID && e instanceof UserPoolClient
98
- ) as UserPoolClient | undefined;
99
-
100
- this.userPoolClient =
101
- existingClient ??
102
- this.userPool.addClient(WEB_CLIENT_ID, {
103
- authFlows: {
104
- userPassword: true,
105
- userSrp: true,
106
- },
107
- });
108
-
109
- this.identityPool.addUserPoolAuthentication(
110
- new UserPoolAuthenticationProvider({
111
- userPool: this.userPool,
112
- userPoolClient: this.userPoolClient,
113
- })
108
+ this.region = Stack.of(this).region;
109
+ this.userPool = this.createUserPool();
110
+ this.userPoolDomain = this.createUserPoolDomain(this.userPool);
111
+ this.userPoolClient = this.createUserPoolClient(this.userPool);
112
+ this.identityPool = this.createIdentityPool(
113
+ this.userPool,
114
+ this.userPoolClient,
114
115
  );
116
+ this.createManagedLoginBranding(
117
+ this.userPool,
118
+ this.userPoolClient,
119
+ this.userPoolDomain,
120
+ );
121
+
122
+ RuntimeConfig.ensure(this).config.cognitoProps = {
123
+ region: Stack.of(this).region,
124
+ identityPoolId: this.identityPool.identityPoolId,
125
+ userPoolId: this.userPool.userPoolId,
126
+ userPoolWebClientId: this.userPoolClient.userPoolClientId,
127
+ };
115
128
 
116
129
  new CfnOutput(this, \`\${id}-UserPoolId\`, {
117
130
  value: this.userPool.userPoolId,
@@ -120,37 +133,10 @@ export class UserIdentity extends Construct {
120
133
  new CfnOutput(this, \`\${id}-IdentityPoolId\`, {
121
134
  value: this.identityPool.identityPoolId,
122
135
  });
123
-
124
- RuntimeConfig.ensure(this).config.cognitoProps = {
125
- region: Stack.of(this).region,
126
- identityPoolId: this.identityPool.identityPoolId,
127
- userPoolId: this.userPool?.userPoolId,
128
- userPoolWebClientId: this.userPoolClient?.userPoolClientId,
129
- };
130
136
  }
131
- }
132
- "
133
- `;
134
137
 
135
- exports[`cognito-auth generator > should generate files > userpool-with-mfa 1`] = `
136
- "/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
137
- SPDX-License-Identifier: Apache-2.0 */
138
- import { PDKNag } from '@aws/pdk/pdk-nag';
139
- import { Duration, Stack } from 'aws-cdk-lib';
140
- import {
141
- AccountRecovery,
142
- AdvancedSecurityMode,
143
- Mfa,
144
- UserPool,
145
- } from 'aws-cdk-lib/aws-cognito';
146
- import { Construct } from 'constructs';
147
-
148
- /**
149
- * Configures a UserPool with MFA across SMS/TOTP using sane defaults.
150
- */
151
- export class UserPoolWithMfa extends UserPool {
152
- constructor(scope: Construct, id: string) {
153
- super(scope, id, {
138
+ private createUserPool = () =>
139
+ new UserPool(this, 'UserPool', {
154
140
  deletionProtection: true,
155
141
  passwordPolicy: {
156
142
  minLength: 8,
@@ -161,9 +147,9 @@ export class UserPoolWithMfa extends UserPool {
161
147
  tempPasswordValidity: Duration.days(3),
162
148
  },
163
149
  mfa: Mfa.REQUIRED,
150
+ featurePlan: FeaturePlan.ESSENTIALS,
164
151
  mfaSecondFactor: { sms: true, otp: true },
165
152
  signInCaseSensitive: false,
166
- advancedSecurityMode: AdvancedSecurityMode.ENFORCED,
167
153
  signInAliases: { username: true, email: true },
168
154
  accountRecovery: AccountRecovery.EMAIL_ONLY,
169
155
  selfSignUpEnabled: true,
@@ -183,25 +169,76 @@ export class UserPoolWithMfa extends UserPool {
183
169
  },
184
170
  });
185
171
 
186
- const stack = Stack.of(this);
187
-
188
- ['AwsSolutions-IAM5', 'AwsPrototyping-IAMNoWildcardPermissions'].forEach(
189
- (RuleId) => {
190
- PDKNag.addResourceSuppressionsByPathNoThrow(
191
- stack,
192
- \`\${PDKNag.getStackPrefix(stack)}\${id}/UserPool/smsRole/Resource\`,
193
- [
194
- {
195
- id: RuleId,
196
- reason:
197
- 'MFA requires sending a text to a users phone number which cannot be known at deployment time.',
198
- appliesTo: ['Resource::*'],
199
- },
200
- ]
201
- );
202
- }
172
+ private createUserPoolDomain = (userPool: UserPool) =>
173
+ new CfnUserPoolDomain(this, 'UserPoolDomain', {
174
+ domain: \`test-\${Stack.of(this).account}\`,
175
+ userPoolId: userPool.userPoolId,
176
+ managedLoginVersion: 2,
177
+ });
178
+
179
+ private createUserPoolClient = (userPool: UserPool) => {
180
+ const lazilyComputedCallbackUrls = Lazy.list({
181
+ produce: () =>
182
+ [
183
+ 'http://localhost:4200',
184
+ \`https://\${Stack.of(this).region}.console.aws.amazon.com\`,
185
+ ].concat(
186
+ this.findCloudFrontDistributions().map(
187
+ (d) => \`https://\${d.domainName}\`,
188
+ ),
189
+ ),
190
+ });
191
+
192
+ return userPool.addClient(WEB_CLIENT_ID, {
193
+ authFlows: {
194
+ userPassword: true,
195
+ userSrp: true,
196
+ user: true,
197
+ },
198
+ oAuth: {
199
+ flows: {
200
+ authorizationCodeGrant: true,
201
+ },
202
+ scopes: [OAuthScope.EMAIL, OAuthScope.OPENID, OAuthScope.PROFILE],
203
+ callbackUrls: lazilyComputedCallbackUrls,
204
+ logoutUrls: lazilyComputedCallbackUrls,
205
+ },
206
+ preventUserExistenceErrors: true,
207
+ });
208
+ };
209
+
210
+ private createIdentityPool = (
211
+ userPool: UserPool,
212
+ userPoolClient: UserPoolClient,
213
+ ) => {
214
+ const identityPool = new IdentityPool(this, 'IdentityPool');
215
+
216
+ identityPool.addUserPoolAuthentication(
217
+ new UserPoolAuthenticationProvider({
218
+ userPool,
219
+ userPoolClient,
220
+ }),
203
221
  );
204
- }
222
+
223
+ return identityPool;
224
+ };
225
+
226
+ private createManagedLoginBranding = (
227
+ userPool: UserPool,
228
+ userPoolClient: UserPoolClient,
229
+ userPoolDomain: CfnUserPoolDomain,
230
+ ) => {
231
+ new CfnManagedLoginBranding(this, 'ManagedLoginBranding', {
232
+ userPoolId: userPool.userPoolId,
233
+ clientId: userPoolClient.userPoolClientId,
234
+ useCognitoProvidedValues: true,
235
+ }).node.addDependency(userPoolClient, userPool, userPoolDomain);
236
+ };
237
+
238
+ private findCloudFrontDistributions = (): Distribution[] =>
239
+ Stack.of(this)
240
+ .node.findAll()
241
+ .filter((child) => child instanceof Distribution);
205
242
  }
206
243
  "
207
244
  `;
@@ -228,6 +265,7 @@ export function App() {
228
265
  `;
229
266
 
230
267
  exports[`cognito-auth generator > should update shared constructs index.ts > common/constructs-index 1`] = `
231
- "export * from './identity/index.js';
232
- export * from './runtime-config/index.js';"
268
+ "export * from './user-identity.js';
269
+ export * from './runtime-config.js';
270
+ "
233
271
  `;
@@ -1,9 +1,7 @@
1
- /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
2
- SPDX-License-Identifier: Apache-2.0 */
3
- import { CognitoAuth as NorthstarCognitoAuth } from '@aws-northstar/ui';
4
- import React, { useContext } from 'react';
5
- import Config from '../../config';
6
- import { RuntimeConfigContext } from '../RuntimeConfig';
1
+ import React, { PropsWithChildren, useEffect } from 'react';
2
+ import { AuthProvider, AuthProviderProps, useAuth } from 'react-oidc-context';
3
+ import { Alert, Spinner } from '@cloudscape-design/components';
4
+ import { useRuntimeConfig } from '../../hooks/useRuntimeConfig';
7
5
 
8
6
  /**
9
7
  * Sets up the Cognito auth.
@@ -11,40 +9,56 @@ import { RuntimeConfigContext } from '../RuntimeConfig';
11
9
  * This assumes a runtime-config.json file is present at '/'. In order for Auth to be set up automatically,
12
10
  * the runtime-config.json must have the cognitoProps set.
13
11
  */
14
- const CognitoAuth: React.FC<any> = ({ children }) => {
15
- const runtimeConfig = useContext(RuntimeConfigContext);
16
-
17
- return runtimeConfig?.cognitoProps ? (
18
- <NorthstarCognitoAuth
19
- header={Config.applicationName}
20
- userPoolId={runtimeConfig.cognitoProps.userPoolId}
21
- clientId={runtimeConfig.cognitoProps.userPoolWebClientId}
22
- region={runtimeConfig.cognitoProps.region}
23
- identityPoolId={runtimeConfig.cognitoProps.identityPoolId}
24
- <%if (allowSignup) {%>allowSignup={true}<% } %>
25
- signUpAttributes={[
26
- {
27
- displayName: 'Email',
28
- name: 'email',
29
- required: true,
30
- },
31
- {
32
- displayName: 'Given name',
33
- name: 'given_name',
34
- required: true,
35
- },
36
- {
37
- displayName: 'Last name',
38
- name: 'family_name',
39
- required: true,
40
- },
41
- ]}
42
- >
43
- {children}
44
- </NorthstarCognitoAuth>
45
- ) : (
46
- <></>
12
+ const CognitoAuth: React.FC<PropsWithChildren> = ({ children }) => {
13
+ const { cognitoProps } = useRuntimeConfig();
14
+
15
+ if (!cognitoProps) {
16
+ return (
17
+ <Alert
18
+ type="error"
19
+ header="Runtime config configuration error"
20
+ >
21
+ The cognitoProps have not been configured in the runtime-config.json.
22
+ </Alert>
23
+ );
24
+ }
25
+
26
+ const cognitoAuthConfig: AuthProviderProps = {
27
+ authority: `https://cognito-idp.${cognitoProps.region}.amazonaws.com/${cognitoProps.userPoolId}`,
28
+ client_id: cognitoProps.userPoolWebClientId,
29
+ redirect_uri: window.location.origin,
30
+ response_type: 'code',
31
+ scope: 'email openid profile',
32
+ };
33
+
34
+ return (
35
+ <AuthProvider {...cognitoAuthConfig}>
36
+ <CognitoAuthInternal>{children}</CognitoAuthInternal>
37
+ </AuthProvider>
47
38
  );
48
39
  };
49
40
 
41
+ const CognitoAuthInternal: React.FC<PropsWithChildren> = ({ children }) => {
42
+ const auth = useAuth();
43
+
44
+ useEffect(() => {
45
+ if (!auth.isAuthenticated && !auth.isLoading) {
46
+ auth.signinRedirect();
47
+ }
48
+ }, [auth])
49
+
50
+ if (auth.isAuthenticated) {
51
+ return children;
52
+ } else if (auth.error) {
53
+ return (
54
+ <Alert type="error" header="Configuration error">
55
+ Error contacting Cognito. Please check your runtime-config.json is
56
+ configured with the correct endpoints.
57
+ </Alert>
58
+ );
59
+ } else {
60
+ return <Spinner />;
61
+ }
62
+ };
63
+
50
64
  export default CognitoAuth;
@@ -0,0 +1,168 @@
1
+ import {
2
+ IdentityPool,
3
+ UserPoolAuthenticationProvider,
4
+ } from '@aws-cdk/aws-cognito-identitypool-alpha';
5
+ import { CfnOutput, Duration, Lazy, Stack } from 'aws-cdk-lib';
6
+ import {
7
+ AccountRecovery,
8
+ CfnManagedLoginBranding,
9
+ CfnUserPoolDomain,
10
+ FeaturePlan,
11
+ Mfa,
12
+ OAuthScope,
13
+ UserPool,
14
+ UserPoolClient,
15
+ } from 'aws-cdk-lib/aws-cognito';
16
+ import { Construct } from 'constructs';
17
+ import { RuntimeConfig } from './runtime-config.js';
18
+ import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
19
+
20
+ const WEB_CLIENT_ID = 'WebClient';
21
+ /**
22
+ * Creates a UserPool and Identity Pool with sane defaults configured intended for usage from a web client.
23
+ */
24
+ export class UserIdentity extends Construct {
25
+ public readonly region: string;
26
+ public readonly identityPool: IdentityPool;
27
+ public readonly userPool: UserPool;
28
+ public readonly userPoolClient: UserPoolClient;
29
+ public readonly userPoolDomain: CfnUserPoolDomain;
30
+
31
+ constructor(scope: Construct, id: string) {
32
+ super(scope, id);
33
+
34
+ this.region = Stack.of(this).region;
35
+ this.userPool = this.createUserPool();
36
+ this.userPoolDomain = this.createUserPoolDomain(this.userPool);
37
+ this.userPoolClient = this.createUserPoolClient(this.userPool);
38
+ this.identityPool = this.createIdentityPool(
39
+ this.userPool,
40
+ this.userPoolClient
41
+ );
42
+ this.createManagedLoginBranding(
43
+ this.userPool,
44
+ this.userPoolClient,
45
+ this.userPoolDomain
46
+ );
47
+
48
+ RuntimeConfig.ensure(this).config.cognitoProps = {
49
+ region: Stack.of(this).region,
50
+ identityPoolId: this.identityPool.identityPoolId,
51
+ userPoolId: this.userPool.userPoolId,
52
+ userPoolWebClientId: this.userPoolClient.userPoolClientId,
53
+ };
54
+
55
+ new CfnOutput(this, `${id}-UserPoolId`, {
56
+ value: this.userPool.userPoolId,
57
+ });
58
+
59
+ new CfnOutput(this, `${id}-IdentityPoolId`, {
60
+ value: this.identityPool.identityPoolId,
61
+ });
62
+ }
63
+
64
+ private createUserPool = () =>
65
+ new UserPool(this, 'UserPool', {
66
+ deletionProtection: true,
67
+ passwordPolicy: {
68
+ minLength: 8,
69
+ requireLowercase: true,
70
+ requireUppercase: true,
71
+ requireDigits: true,
72
+ requireSymbols: true,
73
+ tempPasswordValidity: Duration.days(3),
74
+ },
75
+ mfa: Mfa.REQUIRED,
76
+ featurePlan: FeaturePlan.ESSENTIALS,
77
+ mfaSecondFactor: { sms: true, otp: true },
78
+ signInCaseSensitive: false,
79
+ signInAliases: { username: true, email: true },
80
+ accountRecovery: AccountRecovery.EMAIL_ONLY,
81
+ selfSignUpEnabled: <%= allowSignup %>,
82
+ standardAttributes: {
83
+ phoneNumber: { required: false },
84
+ email: { required: true },
85
+ givenName: { required: true },
86
+ familyName: { required: true },
87
+ },
88
+ autoVerify: {
89
+ email: true,
90
+ phone: true,
91
+ },
92
+ keepOriginal: {
93
+ email: true,
94
+ phone: true,
95
+ },
96
+ });
97
+
98
+ private createUserPoolDomain = (userPool: UserPool) =>
99
+ new CfnUserPoolDomain(this, 'UserPoolDomain', {
100
+ domain: `<%= cognitoDomain %>-${Stack.of(this).account}`,
101
+ userPoolId: userPool.userPoolId,
102
+ managedLoginVersion: 2,
103
+ });
104
+
105
+ private createUserPoolClient = (userPool: UserPool) => {
106
+ const lazilyComputedCallbackUrls = Lazy.list({
107
+ produce: () =>
108
+ [
109
+ 'http://localhost:4200',
110
+ `https://${Stack.of(this).region}.console.aws.amazon.com`,
111
+ ].concat(
112
+ this.findCloudFrontDistributions().map(
113
+ (d) => `https://${d.domainName}`
114
+ )
115
+ ),
116
+ });
117
+
118
+ return userPool.addClient(WEB_CLIENT_ID, {
119
+ authFlows: {
120
+ userPassword: true,
121
+ userSrp: true,
122
+ user: true,
123
+ },
124
+ oAuth: {
125
+ flows: {
126
+ authorizationCodeGrant: true,
127
+ },
128
+ scopes: [OAuthScope.EMAIL, OAuthScope.OPENID, OAuthScope.PROFILE],
129
+ callbackUrls: lazilyComputedCallbackUrls,
130
+ logoutUrls: lazilyComputedCallbackUrls,
131
+ },
132
+ preventUserExistenceErrors: true,
133
+ });
134
+ };
135
+
136
+ private createIdentityPool = (
137
+ userPool: UserPool,
138
+ userPoolClient: UserPoolClient
139
+ ) => {
140
+ const identityPool = new IdentityPool(this, 'IdentityPool');
141
+
142
+ identityPool.addUserPoolAuthentication(
143
+ new UserPoolAuthenticationProvider({
144
+ userPool,
145
+ userPoolClient,
146
+ })
147
+ );
148
+
149
+ return identityPool;
150
+ };
151
+
152
+ private createManagedLoginBranding = (
153
+ userPool: UserPool,
154
+ userPoolClient: UserPoolClient,
155
+ userPoolDomain: CfnUserPoolDomain
156
+ ) => {
157
+ new CfnManagedLoginBranding(this, 'ManagedLoginBranding', {
158
+ userPoolId: userPool.userPoolId,
159
+ clientId: userPoolClient.userPoolClientId,
160
+ useCognitoProvidedValues: true,
161
+ }).node.addDependency(userPoolClient, userPool, userPoolDomain);
162
+ };
163
+
164
+ private findCloudFrontDistributions = (): Distribution[] =>
165
+ Stack.of(this)
166
+ .node.findAll()
167
+ .filter((child) => child instanceof Distribution);
168
+ }