From 190bf28d1b570329f415d2d4c03e608a3b30412b Mon Sep 17 00:00:00 2001 From: Caleb Pollman Date: Mon, 18 Dec 2023 17:35:02 -0800 Subject: [PATCH] fix(authenticator): fix user attribute parsing for amplify >= v6.0.6 (#4861) --- .changeset/swift-mirrors-cheat.md | 5 + docs/package.json | 2 +- examples/angular/package.json | 2 +- examples/next/package.json | 2 +- examples/react-native/package.json | 2 +- examples/vue/package.json | 2 +- .../__tests__/defaultServices.test.ts | 80 ++++++++++-- .../machines/authenticator/defaultServices.ts | 35 ++++-- yarn.lock | 116 +++++++++--------- 9 files changed, 169 insertions(+), 77 deletions(-) create mode 100644 .changeset/swift-mirrors-cheat.md diff --git a/.changeset/swift-mirrors-cheat.md b/.changeset/swift-mirrors-cheat.md new file mode 100644 index 00000000000..44bfb59e8f8 --- /dev/null +++ b/.changeset/swift-mirrors-cheat.md @@ -0,0 +1,5 @@ +--- +"@aws-amplify/ui": patch +--- + +fix(authenticator): fix user attribute parsing for amplify >= v6.0.6 diff --git a/docs/package.json b/docs/package.json index d2f5d8a9b14..9a89fc6661f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -28,7 +28,7 @@ "@mdx-js/loader": "^2.1.0", "@mdx-js/mdx": "^2.1.0", "@mdx-js/react": "^2.1.0", - "aws-amplify": "^6.0.2", + "aws-amplify": "^6.0.6", "countries-list": "^2.6.1", "dotenv": "^16.0.0", "gray-matter": "^4.0.3", diff --git a/examples/angular/package.json b/examples/angular/package.json index cd75db2dc3b..ccb987093de 100644 --- a/examples/angular/package.json +++ b/examples/angular/package.json @@ -21,7 +21,7 @@ "@angular/platform-browser-dynamic": "^14.3.0", "@angular/router": "^14.3.0", "@aws-amplify/ui-angular": "^5.0.5", - "aws-amplify": "^6.0.2", + "aws-amplify": "^6.0.6", "rxjs": "~6.6.0", "tslib": "^2.0.0", "zone.js": "~0.11.4" diff --git a/examples/next/package.json b/examples/next/package.json index 78274c98cce..ae014d26025 100644 --- a/examples/next/package.json +++ b/examples/next/package.json @@ -17,7 +17,7 @@ "@aws-amplify/ui-react-notifications": "^2.0.6", "@aws-amplify/ui-react-storage": "^3.0.7", "@aws-sdk/credential-providers": "^3.370.0", - "aws-amplify": "^6.0.2", + "aws-amplify": "^6.0.6", "next": "^13.5.5", "next-global-css": "^1.1.1", "react": "18.2.0", diff --git a/examples/react-native/package.json b/examples/react-native/package.json index 3e8c84a443d..eaeabb51fa9 100644 --- a/examples/react-native/package.json +++ b/examples/react-native/package.json @@ -21,7 +21,7 @@ "@react-native-async-storage/async-storage": "^1.17.5", "@react-native-community/netinfo": "^8.3.0", "@xstate/react": "^3.2.2", - "aws-amplify": "^6.0.2", + "aws-amplify": "^6.0.6", "react": "18.2.0", "react-native": "0.71.14", "react-native-get-random-values": "^1.9.0", diff --git a/examples/vue/package.json b/examples/vue/package.json index 1092e2ea64b..5f726c8efe5 100644 --- a/examples/vue/package.json +++ b/examples/vue/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@aws-amplify/ui-vue": "^4.0.5", - "aws-amplify": "^6.0.2", + "aws-amplify": "^6.0.6", "vue": "^3.0.5", "vue-router": "4" }, diff --git a/packages/ui/src/machines/authenticator/__tests__/defaultServices.test.ts b/packages/ui/src/machines/authenticator/__tests__/defaultServices.test.ts index 8d1e3009279..a7c67979a0d 100644 --- a/packages/ui/src/machines/authenticator/__tests__/defaultServices.test.ts +++ b/packages/ui/src/machines/authenticator/__tests__/defaultServices.test.ts @@ -1,10 +1,10 @@ -import { Amplify } from 'aws-amplify'; +import { Amplify, ResourcesConfig } from 'aws-amplify'; import { PasswordSettings } from '../../../types'; import { defaultServices } from '../defaultServices'; import { ALLOWED_SPECIAL_CHARACTERS } from '../../../helpers/authenticator/constants'; -jest.mock('aws-amplify'); +const getConfigSpy = jest.spyOn(Amplify, 'getConfig'); const { getAmplifyConfig, @@ -245,15 +245,81 @@ describe('validateConfirmPassword', () => { }); describe('getAmplifyConfig', () => { - // @todo-migration - // think we need to mock result here: - // TypeError: Cannot read properties of undefined (reading 'Auth') - // > 21 | const cliConfig = result.Cognito; - it.skip('should call Amplify.configure', async () => { + it('should call Amplify.getConfig', async () => { await getAmplifyConfig(); expect(Amplify.getConfig).toHaveBeenCalledTimes(1); }); + + it('correctly handles invalid user attributes returned from Amplify.getConfig', async () => { + // previous to aws-amplify@6.0.6, `Amplify.getConfig` returns the wrong shape for `userAttributes` + const invalidConfig: ResourcesConfig = { + Auth: { + Cognito: { + identityPoolId: 'xxxxxx', + allowGuestAccess: true, + // @ts-expect-error + userAttributes: [{ email: { required: true } }], + userPoolClientId: 'xxxxxx', + userPoolId: 'xxxxxx', + mfa: { status: 'off', totpEnabled: false, smsEnabled: true }, + passwordFormat: { + minLength: 8, + requireLowercase: false, + requireUppercase: false, + requireNumbers: false, + requireSpecialCharacters: false, + }, + loginWith: { username: true, email: false, phone: false }, + }, + }, + }; + + getConfigSpy.mockReturnValueOnce(invalidConfig); + + const output = await getAmplifyConfig(); + + expect(output).toStrictEqual({ + ...invalidConfig.Auth.Cognito, + loginMechanisms: ['username'], + socialProviders: undefined, + signUpAttributes: ['email'], + }); + }); + + it('correctly handles user attributes returned from Amplify.getConfig', async () => { + const validConfig: ResourcesConfig = { + Auth: { + Cognito: { + identityPoolId: 'xxxxxx', + allowGuestAccess: true, + userAttributes: { email: { required: true } }, + userPoolClientId: 'xxxxxx', + userPoolId: 'xxxxxx', + mfa: { status: 'off', totpEnabled: false, smsEnabled: true }, + passwordFormat: { + minLength: 8, + requireLowercase: false, + requireUppercase: false, + requireNumbers: false, + requireSpecialCharacters: false, + }, + loginWith: { username: true, email: false, phone: false }, + }, + }, + }; + + getConfigSpy.mockReturnValueOnce(validConfig); + + const output = await getAmplifyConfig(); + + expect(output).toStrictEqual({ + ...validConfig.Auth.Cognito, + loginMechanisms: ['username'], + socialProviders: undefined, + signUpAttributes: ['email'], + }); + }); }); describe('validateFormPassword', () => { diff --git a/packages/ui/src/machines/authenticator/defaultServices.ts b/packages/ui/src/machines/authenticator/defaultServices.ts index ec1863ed1f5..440c88d0d90 100644 --- a/packages/ui/src/machines/authenticator/defaultServices.ts +++ b/packages/ui/src/machines/authenticator/defaultServices.ts @@ -1,4 +1,5 @@ -import { Amplify } from 'aws-amplify'; +import { Amplify, ResourcesConfig } from 'aws-amplify'; +import { UserAttributeKey } from 'aws-amplify/auth'; import { confirmResetPassword, @@ -16,7 +17,6 @@ import { AuthTouchData, LoginMechanism, PasswordSettings, - SignUpAttribute, SocialProvider, ValidatorResult, } from '../../types'; @@ -24,6 +24,31 @@ import { // Cognito does not allow a password length less then 8 characters const DEFAULT_COGNITO_PASSWORD_MIN_LENGTH = 8; +type UserAttributes = ResourcesConfig['Auth']['Cognito']['userAttributes']; +type InvalidUserAttributes = + ResourcesConfig['Auth']['Cognito']['userAttributes'][]; + +const isInvalidUserAtributes = ( + userAttributes: UserAttributes | InvalidUserAttributes +): userAttributes is InvalidUserAttributes => Array.isArray(userAttributes); + +const parseUserAttributes = ( + userAttributes: UserAttributes | InvalidUserAttributes +): UserAttributeKey[] => { + if (!userAttributes) { + return undefined; + } + + // `aws-amplify` versions <= 6.0.5 return an array of `userAttributes` rather than an object + if (isInvalidUserAtributes(userAttributes)) { + return Object.entries(userAttributes).map( + ([_, value]) => Object.keys(value)[0] + ); + } + + return Object.keys(userAttributes); +}; + export const defaultServices = { async getAmplifyConfig() { const result = Amplify.getConfig(); @@ -42,11 +67,7 @@ export const defaultServices = { }) as LoginMechanism[]) : undefined; - const parsedSignupAttributes = userAttributes - ? (Object.entries(userAttributes).map( - ([_key, value]) => Object.keys(value)[0] - ) as SignUpAttribute[]) - : undefined; + const parsedSignupAttributes = parseUserAttributes(userAttributes); const parsedSocialProviders = loginWith?.oauth?.providers ? (loginWith.oauth.providers?.map((provider) => diff --git a/yarn.lock b/yarn.lock index a6731ef6494..8d745eef86d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -436,10 +436,10 @@ resolved "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz#70e45678f06c72fa2e350e8553ec4a4d72b92e06" integrity sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg== -"@aws-amplify/analytics@7.0.2": - version "7.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-7.0.2.tgz#317fbfd326582c27c155c2530020c70e2cfbfe9b" - integrity sha512-PZQddP1kGRNCCDzN8Pj5kI0CappeUsdQtwQdo5UMS4aplgjfuKt17m0xw6SE/6eTIRaf1l0g8sdlCsfN7pDQtQ== +"@aws-amplify/analytics@7.0.8": + version "7.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-7.0.8.tgz#ada0eac2afbef41a4bf09733a857f0243dbb2e85" + integrity sha512-U4FmdXpGWlgkD96Kd3Y53zbhbdyXIo3X4bOoO0gz88tZdmrGEOFepGXURc9xWDhNX9N4//FIj8yvJybPY0RyXA== dependencies: "@aws-sdk/client-firehose" "3.398.0" "@aws-sdk/client-kinesis" "3.398.0" @@ -447,47 +447,47 @@ "@smithy/util-utf8" "2.0.0" tslib "^2.5.0" -"@aws-amplify/api-graphql@4.0.2": - version "4.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/api-graphql/-/api-graphql-4.0.2.tgz#871833a694ecc5b351d385e5d2dd385899ca50ff" - integrity sha512-2GRyvGYq9qCGUb/d9t5letHcTKAgCAvmqZN3Y2MyYWXRD+TwGTW/R8CM+N7uC/9j7S7cPQd09H9bDOH56Otekg== +"@aws-amplify/api-graphql@4.0.8": + version "4.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/api-graphql/-/api-graphql-4.0.8.tgz#02695bf22c6bbc5814bd0eafa22d7f4427ab5508" + integrity sha512-qRsJW7yoGhsjdog8UcEb3i6eikSWHxT1PzeTzZRQR2w/VSmSgt6WFdEFhX0ZcyfPec1n7sHUHiJZbL/KQiFrrQ== dependencies: - "@aws-amplify/api-rest" "4.0.2" - "@aws-amplify/core" "6.0.2" - "@aws-amplify/data-schema-types" "^0.4.2" + "@aws-amplify/api-rest" "4.0.8" + "@aws-amplify/core" "6.0.8" + "@aws-amplify/data-schema-types" "^0.6.10" "@aws-sdk/types" "3.387.0" graphql "15.8.0" rxjs "^7.8.1" tslib "^2.5.0" uuid "^9.0.0" -"@aws-amplify/api-rest@4.0.2": - version "4.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/api-rest/-/api-rest-4.0.2.tgz#1c63b7fa03502d247fe9ce695442655a99214cfd" - integrity sha512-pMNkndD1TJw7/Epeu59Izx67aol8mz55SjtskQT2awIhMFh/J1S2tbkkZ1jZAzKb8oS9jg/+4llRJCEQN/3mdg== +"@aws-amplify/api-rest@4.0.8": + version "4.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/api-rest/-/api-rest-4.0.8.tgz#9eb9e1d6d7873c663646deb750b2b2b7ce6e0732" + integrity sha512-KixtgbuPLWQ4++TSNc9Vxneo9Zko+OmcM6zC5cu+zhq1+Pid8Xz+woR/xoxDCFbLTQwqyCpBvrF/TyJmecbLNg== dependencies: tslib "^2.5.0" -"@aws-amplify/api@6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/api/-/api-6.0.2.tgz#8b9d6edb2cde3eb0c56b84020ab601fed54409db" - integrity sha512-YhZa1jP9gh1Mfu73/x0TSz4CNMWbSdepQDjbyseRQGxwBRKQOG//bIcjup9LgCqmZlpwCbAOQdfPgAsReTFtHQ== +"@aws-amplify/api@6.0.8": + version "6.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/api/-/api-6.0.8.tgz#6a8f92ea39db4c18cc2a5b3e0d23bef5ef1969c7" + integrity sha512-9V+fD8dbNHQSB1wl5I8+oJay7uBJgjsqnLSPXANN3M/b7hcGDo1U/ZA2woR1OG1O8C7DS8b/f27Jntfb0lbh4A== dependencies: - "@aws-amplify/api-graphql" "4.0.2" - "@aws-amplify/api-rest" "4.0.2" + "@aws-amplify/api-graphql" "4.0.8" + "@aws-amplify/api-rest" "4.0.8" tslib "^2.5.0" -"@aws-amplify/auth@6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/auth/-/auth-6.0.2.tgz#b4d5e2bb54c74d39617fb6c22217b699fa7ea648" - integrity sha512-J5sRa93yX6t3lo4HRI0jmrZ2QGAOENdn7fg+JR7NihoQpa+pmPZ6Z9B55Rt5zzqqMTipLCI4t98nhp7gexRj0A== +"@aws-amplify/auth@6.0.8": + version "6.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/auth/-/auth-6.0.8.tgz#c28c96770e995c64707578ac057c48bee630f373" + integrity sha512-MCbqfoujW1PryBZ/Lz9wwne6gt2n3zziNz0pyLy6IGLLo5pGb029Nz9V0ODH4//UbGdUU2i/4c0eb05hXcycCg== dependencies: tslib "^2.5.0" -"@aws-amplify/core@6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/core/-/core-6.0.2.tgz#274dd15eb85c260a96f7a071894839f6dcbfa1d0" - integrity sha512-PzOBZbelbOFhNRCj+PpV0lzWPEInB3TN8Yp0aNj8u+qy2+je8L3EQIPSw367KB3Ix69XhWzd9uLd6W2/ZDGk+Q== +"@aws-amplify/core@6.0.8": + version "6.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/core/-/core-6.0.8.tgz#3033014895ace0c2865f4a094957e9d51048a175" + integrity sha512-k6QdZXAIoS2OLmnWJ/54h4J6qIJFfup5DfefT3REgi559lgLE+cG9eTMLpA5x9ZUNm5jvgSwrQzJkLnZshq6ew== dependencies: "@aws-crypto/sha256-js" "5.2.0" "@aws-sdk/types" "3.398.0" @@ -498,19 +498,19 @@ tslib "^2.5.0" uuid "^9.0.0" -"@aws-amplify/data-schema-types@^0.4.2": - version "0.4.2" - resolved "https://registry.npmjs.org/@aws-amplify/data-schema-types/-/data-schema-types-0.4.2.tgz#42a63fbc97922e5f74ff5b2780145d1bdc35d80e" - integrity sha512-ip5U1FisKxCAgIupo5FxoJVsWedKOl1UIJrUOpMWBtSnhCeVDJerNyaH7Su5YxmOX4ZpG7SAMF9qwF5C1zIKgg== +"@aws-amplify/data-schema-types@^0.6.10": + version "0.6.10" + resolved "https://registry.npmjs.org/@aws-amplify/data-schema-types/-/data-schema-types-0.6.10.tgz#e208e57dd2e7de0b9d479d19c1d8459b578df506" + integrity sha512-o893k1tNJ0iR9w9Q/jymhSQZmgNdH/L5tz+RXyWcQO+qgN3XhGaayqjYKcQ22XkB1pBgGkXtRLO6Jg74KriBWg== dependencies: rxjs "^7.8.1" -"@aws-amplify/datastore@5.0.2": - version "5.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/datastore/-/datastore-5.0.2.tgz#3e318993462b16ed892b51637793f6bc89c6e593" - integrity sha512-GWYhEBHrHZsugUriY5cTs0TXMQ9vzaibOhnXxE9LZlYCHaMAAzq15rspVt4wxD6hZgCyS3PX1qqeSudT/anf8g== +"@aws-amplify/datastore@5.0.8": + version "5.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/datastore/-/datastore-5.0.8.tgz#748ba5d2b176cabb3ce1ea3ddc67a3c12dc006d6" + integrity sha512-GXEAir0iKZ3a8WKmlTNv48LqJs26O3LpV9gmnbZsvALU62Jk+uCu0ABnfb2daLus/7v8OyIRWfunSgRP/UMtpQ== dependencies: - "@aws-amplify/api" "6.0.2" + "@aws-amplify/api" "6.0.8" buffer "4.9.2" idb "5.0.6" immer "9.0.6" @@ -527,10 +527,10 @@ camelcase-keys "6.2.2" tslib "^2.5.0" -"@aws-amplify/notifications@2.0.2": - version "2.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/notifications/-/notifications-2.0.2.tgz#a6935b5de3b35b9b2c5309b2f86e7977e52620af" - integrity sha512-Var20p9r3d2qXYdnb2WCEkq74KtmrbOc/nIaCrWQ/jptodeIoVWi5D7dvDDFA84yIPi88DqyBdKJW5n0iB+w2Q== +"@aws-amplify/notifications@2.0.8": + version "2.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/notifications/-/notifications-2.0.8.tgz#5deafd86f2d2463635e4e6776befdcd336dd4925" + integrity sha512-gm+yLdSJQ0hhQHEQsDexA1x/RKIsz8DM48MEwJy6CNMYLMi2pBTu+j1MS0Zp8l1Z+0rm/K6PV44APpuWrXoA4g== dependencies: lodash "^4.17.21" tslib "^2.5.0" @@ -558,10 +558,10 @@ resolved "https://registry.npmjs.org/@aws-amplify/rtn-web-browser/-/rtn-web-browser-1.0.2.tgz#32de308b2efd7b24f484c8d51443aea26fdbdaf1" integrity sha512-r0GceWySsvoR9nkk3PDObSr4fOvMcvJpfcfxoVfYgPLks//iXDRTnRz6sP4OMvCior7KwHekUnuOYcRpLQnxuw== -"@aws-amplify/storage@6.0.2": - version "6.0.2" - resolved "https://registry.npmjs.org/@aws-amplify/storage/-/storage-6.0.2.tgz#0ca9159e123ec47d7634bf547612a0e90a9da1de" - integrity sha512-Jp768kOwUPdB1lddPErPRmTyRt5KAY+ICTI128c2Wn2ChdlE2GfKF1xC4Bu98Lcwc6BvGlqPdDrLe3l/0v8NEw== +"@aws-amplify/storage@6.0.8": + version "6.0.8" + resolved "https://registry.npmjs.org/@aws-amplify/storage/-/storage-6.0.8.tgz#9892360d1a6a50b78c8f4a514c1c78b0a73cdbc0" + integrity sha512-L/jP5f7Se76U2/TMAuoTkTo7sHQpBL3oqY0LgYPMLr/uppyZOVlJMsMXSIVUuXR6FBRVHgJv+qFWYrG9wDZ6NA== dependencies: "@aws-sdk/types" "3.398.0" "@smithy/md5-js" "2.0.7" @@ -9802,18 +9802,18 @@ available-typed-arrays@^1.0.5: resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -aws-amplify@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/aws-amplify/-/aws-amplify-6.0.2.tgz#fdf1e6a982937673a34b05944e477b2559e6e036" - integrity sha512-fsBvPHXze7ZvbsVqYsAYe6NccLO9L525+JWXKW8nkoZP3xOSJLEr6/x6S8dta5qutLPgymiFrdRY/bEwel21qg== - dependencies: - "@aws-amplify/analytics" "7.0.2" - "@aws-amplify/api" "6.0.2" - "@aws-amplify/auth" "6.0.2" - "@aws-amplify/core" "6.0.2" - "@aws-amplify/datastore" "5.0.2" - "@aws-amplify/notifications" "2.0.2" - "@aws-amplify/storage" "6.0.2" +aws-amplify@^6.0.6: + version "6.0.8" + resolved "https://registry.npmjs.org/aws-amplify/-/aws-amplify-6.0.8.tgz#0dcf19e965d4b3f22c0aa83223c1c55676c0c737" + integrity sha512-WzK5XE9XtYagP8dA/z9HO196OvW9sbZNilKCFxWxXuYcYWJeYYyRPaBK0h4xSY5N3EO8gl+RZeHSAuOzibX8MQ== + dependencies: + "@aws-amplify/analytics" "7.0.8" + "@aws-amplify/api" "6.0.8" + "@aws-amplify/auth" "6.0.8" + "@aws-amplify/core" "6.0.8" + "@aws-amplify/datastore" "5.0.8" + "@aws-amplify/notifications" "2.0.8" + "@aws-amplify/storage" "6.0.8" tslib "^2.5.0" aws-sign2@~0.7.0: