From 9bec890e6fd7d41c319c2a6f1d06ad98923214f0 Mon Sep 17 00:00:00 2001 From: Gao Sun Date: Tue, 10 Jan 2023 18:05:28 +0800 Subject: [PATCH] refactor(core): migrate social library to factory mode --- packages/core/src/libraries/social.ts | 127 ++++++++++-------- .../core/src/routes/interaction/index.test.ts | 41 +++--- packages/core/src/routes/interaction/index.ts | 4 +- .../utils/social-verification.test.ts | 11 +- .../interaction/utils/social-verification.ts | 16 ++- .../identifier-payload-verification.test.ts | 2 +- .../identifier-payload-verification.ts | 4 +- .../identifier-verification.test.ts | 12 +- .../verifications/identifier-verification.ts | 10 +- .../user-identity-verification.test.ts | 30 +++-- .../user-identity-verification.ts | 18 ++- packages/core/src/tenants/Libraries.ts | 2 + 12 files changed, 155 insertions(+), 122 deletions(-) diff --git a/packages/core/src/libraries/social.ts b/packages/core/src/libraries/social.ts index dd04f277a..9e46950ff 100644 --- a/packages/core/src/libraries/social.ts +++ b/packages/core/src/libraries/social.ts @@ -7,8 +7,8 @@ import type { InteractionResults } from 'oidc-provider'; import { z } from 'zod'; import RequestError from '#src/errors/RequestError/index.js'; -import { getLogtoConnectorById } from '#src/libraries/connector.js'; -import { findUserByEmail, findUserByPhone } from '#src/queries/user.js'; +import type { ConnectorLibrary } from '#src/libraries/connector.js'; +import type Queries from '#src/tenants/Queries.js'; import assertThat from '#src/utils/assert-that.js'; export type SocialUserInfoSession = { @@ -16,42 +16,7 @@ export type SocialUserInfoSession = { userInfo: SocialUserInfo; }; -const getConnector = async (connectorId: string) => { - try { - return await getLogtoConnectorById(connectorId); - } catch (error: unknown) { - // Throw a new error with status 422 when connector not found. - if (error instanceof RequestError && error.code === 'entity.not_found') { - throw new RequestError({ - code: 'session.invalid_connector_id', - status: 422, - connectorId, - }); - } - throw error; - } -}; - -export const getUserInfoByAuthCode = async ( - connectorId: string, - data: unknown, - getConnectorSession?: GetSession -): Promise => { - const connector = await getConnector(connectorId); - - assertThat( - connector.type === ConnectorType.Social, - new RequestError({ - code: 'session.invalid_connector_id', - status: 422, - connectorId, - }) - ); - - return connector.getUserInfo(data, getConnectorSession); -}; - -export const getUserInfoFromInteractionResult = async ( +const getUserInfoFromInteractionResult = async ( connectorId: string, interactionResult: InteractionResults ): Promise => { @@ -74,31 +39,75 @@ export const getUserInfoFromInteractionResult = async ( return result.socialUserInfo.userInfo; }; -/** - * Find user by phone/email from social user info. - * if both phone and email exist, take phone for priority. - * - * @param info SocialUserInfo - * @returns null | [string, User] the first string indicating phone or email - */ -export const findSocialRelatedUser = async ( - info: SocialUserInfo -): Promise> => { - if (info.phone) { - const user = await findUserByPhone(info.phone); +export type SocialLibrary = ReturnType; - if (user) { - return [{ type: 'phone', value: info.phone }, user]; +export const createSocialLibrary = (queries: Queries, connectorLibrary: ConnectorLibrary) => { + const { findUserByEmail, findUserByPhone } = queries.users; + const { getLogtoConnectorById } = connectorLibrary; + + const getConnector = async (connectorId: string) => { + try { + return await getLogtoConnectorById(connectorId); + } catch (error: unknown) { + // Throw a new error with status 422 when connector not found. + if (error instanceof RequestError && error.code === 'entity.not_found') { + throw new RequestError({ + code: 'session.invalid_connector_id', + status: 422, + connectorId, + }); + } + throw error; } - } + }; - if (info.email) { - const user = await findUserByEmail(info.email); + const getUserInfoByAuthCode = async ( + connectorId: string, + data: unknown, + getConnectorSession?: GetSession + ): Promise => { + const connector = await getConnector(connectorId); - if (user) { - return [{ type: 'email', value: info.email }, user]; + assertThat( + connector.type === ConnectorType.Social, + new RequestError({ + code: 'session.invalid_connector_id', + status: 422, + connectorId, + }) + ); + + return connector.getUserInfo(data, getConnectorSession); + }; + + /** + * Find user by phone/email from social user info. + * if both phone and email exist, take phone for priority. + * + * @param info SocialUserInfo + * @returns null | [string, User] the first string indicating phone or email + */ + const findSocialRelatedUser = async ( + info: SocialUserInfo + ): Promise> => { + if (info.phone) { + const user = await findUserByPhone(info.phone); + + if (user) { + return [{ type: 'phone', value: info.phone }, user]; + } } - } - return null; + if (info.email) { + const user = await findUserByEmail(info.email); + + if (user) { + return [{ type: 'email', value: info.email }, user]; + } + } + + return null; + }; + + return { getUserInfoByAuthCode, getUserInfoFromInteractionResult, findSocialRelatedUser }; }; diff --git a/packages/core/src/routes/interaction/index.test.ts b/packages/core/src/routes/interaction/index.test.ts index 3971826b9..5f73bbc09 100644 --- a/packages/core/src/routes/interaction/index.test.ts +++ b/packages/core/src/routes/interaction/index.test.ts @@ -6,7 +6,9 @@ import { mockSignInExperience } from '#src/__mocks__/sign-in-experience.js'; import RequestError from '#src/errors/RequestError/index.js'; import type koaAuditLog from '#src/middleware/koa-audit-log.js'; import { createMockLogContext } from '#src/test-utils/koa-audit-log.js'; -import { createMockTenantWithInteraction } from '#src/test-utils/tenant.js'; +import { createMockProvider } from '#src/test-utils/oidc-provider.js'; +import { createMockTenantWithInteraction, MockTenant } from '#src/test-utils/tenant.js'; +import type { LogtoConnector } from '#src/utils/connectors/types.js'; import { createRequester } from '#src/utils/test-utils.js'; import { verificationPath, interactionPrefix } from './const.js'; @@ -33,21 +35,6 @@ const getLogtoConnectorByIdHelper = jest.fn(async (connectorId: string) => { }; }); -await mockEsmWithActual('#src/libraries/connector.js', () => ({ - getLogtoConnectorById: jest.fn(async (connectorId: string) => { - const connector = await getLogtoConnectorByIdHelper(connectorId); - - if (connector.type !== ConnectorType.Social) { - throw new RequestError({ - code: 'entity.not_found', - status: 404, - }); - } - - return connector; - }), -})); - await mockEsmWithActual('#src/libraries/sign-in-experience/index.js', () => ({ getSignInExperienceForApplication: jest.fn().mockResolvedValue(mockSignInExperience), })); @@ -119,7 +106,27 @@ describe('interaction routes', () => { const sessionRequest = createRequester({ anonymousRoutes: interactionRoutes, - tenantContext: createMockTenantWithInteraction(jest.fn().mockResolvedValue(baseProviderMock)), + tenantContext: new MockTenant( + createMockProvider(jest.fn().mockResolvedValue(baseProviderMock)), + undefined, + { + connectors: { + getLogtoConnectorById: async (connectorId: string) => { + const connector = await getLogtoConnectorByIdHelper(connectorId); + + if (connector.type !== ConnectorType.Social) { + throw new RequestError({ + code: 'entity.not_found', + status: 404, + }); + } + + // @ts-expect-error + return connector as LogtoConnector; + }, + }, + } + ), }); afterEach(() => { diff --git a/packages/core/src/routes/interaction/index.ts b/packages/core/src/routes/interaction/index.ts index 6daea338a..37490743f 100644 --- a/packages/core/src/routes/interaction/index.ts +++ b/packages/core/src/routes/interaction/index.ts @@ -289,7 +289,7 @@ export default function interactionRoutes( const log = createLog(`Interaction.${event}.Submit`); log.append({ interaction: interactionStorage }); - const accountVerifiedInteraction = await verifyIdentifier(ctx, provider, interactionStorage); + const accountVerifiedInteraction = await verifyIdentifier(ctx, tenant, interactionStorage); const verifiedInteraction = await verifyProfile(accountVerifiedInteraction); @@ -316,7 +316,7 @@ export default function interactionRoutes( log.append(payload); - const redirectTo = await createSocialAuthorizationUrl(ctx, provider, payload); + const redirectTo = await createSocialAuthorizationUrl(ctx, tenant, payload); ctx.body = { redirectTo }; diff --git a/packages/core/src/routes/interaction/utils/social-verification.test.ts b/packages/core/src/routes/interaction/utils/social-verification.test.ts index 1bf750835..acb54b369 100644 --- a/packages/core/src/routes/interaction/utils/social-verification.test.ts +++ b/packages/core/src/routes/interaction/utils/social-verification.test.ts @@ -4,14 +4,14 @@ import { createMockUtils } from '@logto/shared/esm'; import type { WithLogContext } from '#src/middleware/koa-audit-log.js'; import createMockContext from '#src/test-utils/jest-koa-mocks/create-mock-context.js'; import { createMockLogContext } from '#src/test-utils/koa-audit-log.js'; -import { createMockProvider } from '#src/test-utils/oidc-provider.js'; +import { MockTenant } from '#src/test-utils/tenant.js'; const { jest } = import.meta; const { mockEsm } = createMockUtils(jest); -const { getUserInfoByAuthCode } = mockEsm('#src/libraries/social.js', () => ({ - getUserInfoByAuthCode: jest.fn().mockResolvedValue({ id: 'foo' }), -})); +const getUserInfoByAuthCode = jest.fn().mockResolvedValue({ id: 'foo' }); + +const tenant = new MockTenant(undefined, undefined, { socials: { getUserInfoByAuthCode } }); mockEsm('#src/libraries/connector.js', () => ({ getLogtoConnectorById: jest.fn().mockResolvedValue({ @@ -27,7 +27,6 @@ const { verifySocialIdentity } = await import('./social-verification.js'); describe('social-verification', () => { it('verifySocialIdentity', async () => { - const provider = createMockProvider(); // @ts-expect-error test mock context const ctx: WithLogContext = { ...createMockContext(), @@ -35,7 +34,7 @@ describe('social-verification', () => { }; const connectorId = 'connector'; const connectorData = { authCode: 'code' }; - const userInfo = await verifySocialIdentity({ connectorId, connectorData }, ctx, provider); + const userInfo = await verifySocialIdentity({ connectorId, connectorData }, ctx, tenant); expect(getUserInfoByAuthCode).toBeCalledWith(connectorId, connectorData, expect.anything()); expect(userInfo).toEqual({ id: 'foo' }); diff --git a/packages/core/src/routes/interaction/utils/social-verification.ts b/packages/core/src/routes/interaction/utils/social-verification.ts index bab12886a..5d01c8fff 100644 --- a/packages/core/src/routes/interaction/utils/social-verification.ts +++ b/packages/core/src/routes/interaction/utils/social-verification.ts @@ -1,24 +1,26 @@ import type { ConnectorSession, SocialUserInfo } from '@logto/connector-kit'; import type { SocialConnectorPayload } from '@logto/schemas'; import { ConnectorType } from '@logto/schemas'; -import type Provider from 'oidc-provider'; -import { getLogtoConnectorById } from '#src/libraries/connector.js'; -import { getUserInfoByAuthCode } from '#src/libraries/social.js'; import type { WithLogContext } from '#src/middleware/koa-audit-log.js'; import { getConnectorSessionResult, assignConnectorSessionResult, } from '#src/routes/interaction/utils/interaction.js'; +import type TenantContext from '#src/tenants/TenantContext.js'; import assertThat from '#src/utils/assert-that.js'; import type { SocialAuthorizationUrlPayload } from '../types/index.js'; export const createSocialAuthorizationUrl = async ( ctx: WithLogContext, - provider: Provider, + { provider, libraries }: TenantContext, payload: SocialAuthorizationUrlPayload ) => { + const { + connectors: { getLogtoConnectorById }, + } = libraries; + const { connectorId, state, redirectUri } = payload; assertThat(state && redirectUri, 'session.insufficient_info'); @@ -40,8 +42,12 @@ export const createSocialAuthorizationUrl = async ( export const verifySocialIdentity = async ( { connectorId, connectorData }: SocialConnectorPayload, ctx: WithLogContext, - provider: Provider + { provider, libraries }: TenantContext ): Promise => { + const { + socials: { getUserInfoByAuthCode }, + } = libraries; + const log = ctx.createLog('Interaction.SignIn.Identifier.Social.Submit'); log.append({ connectorId, connectorData }); diff --git a/packages/core/src/routes/interaction/verifications/identifier-payload-verification.test.ts b/packages/core/src/routes/interaction/verifications/identifier-payload-verification.test.ts index 8714863ad..af9ccd55c 100644 --- a/packages/core/src/routes/interaction/verifications/identifier-payload-verification.test.ts +++ b/packages/core/src/routes/interaction/verifications/identifier-payload-verification.test.ts @@ -163,7 +163,7 @@ describe('identifier verification', () => { interactionStorage ); - expect(verifySocialIdentity).toBeCalledWith(identifier, baseCtx, tenant.provider); + expect(verifySocialIdentity).toBeCalledWith(identifier, baseCtx, tenant); expect(findUserByIdentifier).not.toBeCalled(); expect(result).toEqual({ diff --git a/packages/core/src/routes/interaction/verifications/identifier-payload-verification.ts b/packages/core/src/routes/interaction/verifications/identifier-payload-verification.ts index 9ea5be42e..9c4316635 100644 --- a/packages/core/src/routes/interaction/verifications/identifier-payload-verification.ts +++ b/packages/core/src/routes/interaction/verifications/identifier-payload-verification.ts @@ -68,9 +68,9 @@ const verifyVerificationCodeIdentifier = async ( const verifySocialIdentifier = async ( identifier: SocialConnectorPayload, ctx: WithLogContext, - { provider }: TenantContext + tenant: TenantContext ): Promise => { - const userInfo = await verifySocialIdentity(identifier, ctx, provider); + const userInfo = await verifySocialIdentity(identifier, ctx, tenant); return { key: 'social', connectorId: identifier.connectorId, userInfo }; }; diff --git a/packages/core/src/routes/interaction/verifications/identifier-verification.test.ts b/packages/core/src/routes/interaction/verifications/identifier-verification.test.ts index b95972c48..9a4447411 100644 --- a/packages/core/src/routes/interaction/verifications/identifier-verification.test.ts +++ b/packages/core/src/routes/interaction/verifications/identifier-verification.test.ts @@ -2,7 +2,7 @@ import { InteractionEvent } from '@logto/schemas'; import { createMockUtils, pickDefault } from '@logto/shared/esm'; import { createMockLogContext } from '#src/test-utils/koa-audit-log.js'; -import { createMockProvider } from '#src/test-utils/oidc-provider.js'; +import { MockTenant } from '#src/test-utils/tenant.js'; import { createContextWithRouteParameters } from '#src/utils/test-utils.js'; import type { SignInInteractionResult } from '../types/index.js'; @@ -22,7 +22,7 @@ describe('verifyIdentifier', () => { ...createContextWithRouteParameters(), ...createMockLogContext(), }; - const provider = createMockProvider(); + const tenant = new MockTenant(); afterEach(() => { jest.clearAllMocks(); @@ -33,7 +33,7 @@ describe('verifyIdentifier', () => { event: InteractionEvent.Register, }; - const result = await verifyIdentifier(ctx, provider, interactionRecord); + const result = await verifyIdentifier(ctx, tenant, interactionRecord); expect(result).toBe(interactionRecord); expect(verifyUserAccount).not.toBeCalled(); @@ -53,10 +53,10 @@ describe('verifyIdentifier', () => { verifyUserAccount.mockResolvedValue(verifiedRecord); - const result = await verifyIdentifier(ctx, provider, interactionRecord); + const result = await verifyIdentifier(ctx, tenant, interactionRecord); expect(result).toBe(verifiedRecord); - expect(verifyUserAccount).toBeCalledWith(interactionRecord); - expect(storeInteractionResult).toBeCalledWith(verifiedRecord, ctx, provider); + expect(verifyUserAccount).toBeCalledWith(interactionRecord, tenant.libraries.socials); + expect(storeInteractionResult).toBeCalledWith(verifiedRecord, ctx, tenant.provider); }); }); diff --git a/packages/core/src/routes/interaction/verifications/identifier-verification.ts b/packages/core/src/routes/interaction/verifications/identifier-verification.ts index 5c7820fd2..980d312eb 100644 --- a/packages/core/src/routes/interaction/verifications/identifier-verification.ts +++ b/packages/core/src/routes/interaction/verifications/identifier-verification.ts @@ -1,6 +1,7 @@ import { InteractionEvent } from '@logto/schemas'; import type { Context } from 'koa'; -import type Provider from 'oidc-provider'; + +import type TenantContext from '#src/tenants/TenantContext.js'; import type { RegisterInteractionResult, @@ -18,7 +19,7 @@ type InteractionResult = export default async function verifyIdentifier( ctx: Context, - provider: Provider, + { provider, libraries }: TenantContext, interactionRecord: InteractionResult ): Promise { if (interactionRecord.event === InteractionEvent.Register) { @@ -26,7 +27,10 @@ export default async function verifyIdentifier( } // Verify the user account and assign the verified result to the interaction record - const accountVerifiedInteractionResult = await verifyUserAccount(interactionRecord); + const accountVerifiedInteractionResult = await verifyUserAccount( + interactionRecord, + libraries.socials + ); await storeInteractionResult(accountVerifiedInteractionResult, ctx, provider); return accountVerifiedInteractionResult; diff --git a/packages/core/src/routes/interaction/verifications/user-identity-verification.test.ts b/packages/core/src/routes/interaction/verifications/user-identity-verification.test.ts index 025b087f9..516b467e5 100644 --- a/packages/core/src/routes/interaction/verifications/user-identity-verification.test.ts +++ b/packages/core/src/routes/interaction/verifications/user-identity-verification.test.ts @@ -2,6 +2,7 @@ import { InteractionEvent } from '@logto/schemas'; import { createMockUtils, pickDefault } from '@logto/shared/esm'; import RequestError from '#src/errors/RequestError/index.js'; +import type { SocialLibrary } from '#src/libraries/social.js'; import type { SignInInteractionResult } from '../types/index.js'; @@ -10,9 +11,10 @@ const { mockEsm, mockEsmDefault } = createMockUtils(jest); const findUserByIdentifier = mockEsmDefault('../utils/find-user-by-identifier.js', () => jest.fn()); -mockEsm('#src/libraries/social.js', () => ({ +// @ts-expect-error +const socialLibrary: SocialLibrary = { findSocialRelatedUser: jest.fn().mockResolvedValue(null), -})); +}; const verifyUserAccount = await pickDefault(import('./user-identity-verification.js')); @@ -28,7 +30,7 @@ describe('verifyUserAccount', () => { event: InteractionEvent.SignIn, }; - await expect(verifyUserAccount(interaction)).rejects.toMatchError( + await expect(verifyUserAccount(interaction, socialLibrary)).rejects.toMatchError( new RequestError({ code: 'session.identifier_not_found', status: 404 }) ); }); @@ -39,7 +41,7 @@ describe('verifyUserAccount', () => { identifiers: [{ key: 'accountId', value: 'foo' }], }; - const result = await verifyUserAccount(interaction); + const result = await verifyUserAccount(interaction, socialLibrary); expect(result).toEqual({ ...interaction, accountId: 'foo' }); }); @@ -52,7 +54,7 @@ describe('verifyUserAccount', () => { identifiers: [{ key: 'emailVerified', value: 'email' }], }; - const result = await verifyUserAccount(interaction); + const result = await verifyUserAccount(interaction, socialLibrary); expect(findUserByIdentifierMock).toBeCalledWith({ email: 'email' }); expect(result).toEqual({ ...interaction, accountId: 'foo' }); @@ -66,7 +68,7 @@ describe('verifyUserAccount', () => { identifiers: [{ key: 'phoneVerified', value: '123456' }], }; - const result = await verifyUserAccount(interaction); + const result = await verifyUserAccount(interaction, socialLibrary); expect(findUserByIdentifierMock).toBeCalledWith({ phone: '123456' }); expect(result).toEqual({ ...interaction, accountId: 'foo' }); @@ -80,7 +82,7 @@ describe('verifyUserAccount', () => { identifiers: [{ key: 'social', connectorId: 'connectorId', userInfo: { id: 'foo' } }], }; - const result = await verifyUserAccount(interaction); + const result = await verifyUserAccount(interaction, socialLibrary); expect(findUserByIdentifierMock).toBeCalledWith({ connectorId: 'connectorId', userInfo: { id: 'foo' }, @@ -97,7 +99,7 @@ describe('verifyUserAccount', () => { identifiers: [{ key: 'social', connectorId: 'connectorId', userInfo: { id: 'foo' } }], }; - await expect(verifyUserAccount(interaction)).rejects.toMatchError( + await expect(verifyUserAccount(interaction, socialLibrary)).rejects.toMatchError( new RequestError( { code: 'user.identity_not_exist', @@ -124,7 +126,7 @@ describe('verifyUserAccount', () => { ], }; - const result = await verifyUserAccount(interaction); + const result = await verifyUserAccount(interaction, socialLibrary); expect(findUserByIdentifierMock).toBeCalledWith({ email: 'email' }); expect(result).toEqual({ ...interaction, accountId: 'foo' }); @@ -141,7 +143,7 @@ describe('verifyUserAccount', () => { ], }; - await expect(verifyUserAccount(interaction)).rejects.toMatchError( + await expect(verifyUserAccount(interaction, socialLibrary)).rejects.toMatchError( new RequestError({ code: 'user.user_not_exist', status: 404 }, { identifier: 'email' }) ); @@ -161,7 +163,7 @@ describe('verifyUserAccount', () => { ], }; - await expect(verifyUserAccount(interaction)).rejects.toMatchError( + await expect(verifyUserAccount(interaction, socialLibrary)).rejects.toMatchError( new RequestError({ code: 'user.suspended', status: 401 }) ); @@ -182,7 +184,7 @@ describe('verifyUserAccount', () => { ], }; - await expect(verifyUserAccount(interaction)).rejects.toMatchError( + await expect(verifyUserAccount(interaction, socialLibrary)).rejects.toMatchError( new RequestError('session.verification_failed') ); expect(findUserByIdentifierMock).toHaveBeenNthCalledWith(1, { email: 'email' }); @@ -198,7 +200,7 @@ describe('verifyUserAccount', () => { identifiers: [{ key: 'emailVerified', value: 'email' }], }; - await expect(verifyUserAccount(interaction)).rejects.toMatchError( + await expect(verifyUserAccount(interaction, socialLibrary)).rejects.toMatchError( new RequestError('session.verification_failed') ); expect(findUserByIdentifierMock).toBeCalledWith({ email: 'email' }); @@ -220,7 +222,7 @@ describe('verifyUserAccount', () => { }, }; - const result = await verifyUserAccount(interaction); + const result = await verifyUserAccount(interaction, socialLibrary); expect(findUserByIdentifierMock).toBeCalledWith({ email: 'email' }); expect(result).toEqual({ ...interaction, accountId: 'foo' }); diff --git a/packages/core/src/routes/interaction/verifications/user-identity-verification.ts b/packages/core/src/routes/interaction/verifications/user-identity-verification.ts index fdb4aeb27..5f1e6dcfc 100644 --- a/packages/core/src/routes/interaction/verifications/user-identity-verification.ts +++ b/packages/core/src/routes/interaction/verifications/user-identity-verification.ts @@ -1,7 +1,7 @@ import { deduplicate } from '@silverhand/essentials'; import RequestError from '#src/errors/RequestError/index.js'; -import { findSocialRelatedUser } from '#src/libraries/social.js'; +import type { SocialLibrary } from '#src/libraries/social.js'; import assertThat from '#src/utils/assert-that.js'; import { maskUserInfo } from '#src/utils/format.js'; @@ -36,13 +36,16 @@ const identifyUserByVerifiedEmailOrPhone = async ( return id; }; -const identifyUserBySocialIdentifier = async (identifier: SocialIdentifier) => { +const identifyUserBySocialIdentifier = async ( + identifier: SocialIdentifier, + socialLibrary: SocialLibrary +) => { const { connectorId, userInfo } = identifier; const user = await findUserByIdentifier({ connectorId, userInfo }); if (!user) { - const relatedInfo = await findSocialRelatedUser(userInfo); + const relatedInfo = await socialLibrary.findSocialRelatedUser(userInfo); throw new RequestError( { @@ -60,9 +63,9 @@ const identifyUserBySocialIdentifier = async (identifier: SocialIdentifier) => { return id; }; -const identifyUser = async (identifier: Identifier) => { +const identifyUser = async (identifier: Identifier, socialLibrary: SocialLibrary) => { if (identifier.key === 'social') { - return identifyUserBySocialIdentifier(identifier); + return identifyUserBySocialIdentifier(identifier, socialLibrary); } if (identifier.key === 'accountId') { @@ -73,7 +76,8 @@ const identifyUser = async (identifier: Identifier) => { }; export default async function verifyUserAccount( - interaction: SignInInteractionResult | ForgotPasswordInteractionResult + interaction: SignInInteractionResult | ForgotPasswordInteractionResult, + socialLibrary: SocialLibrary ): Promise { const { identifiers = [], accountId, profile } = interaction; @@ -91,7 +95,7 @@ export default async function verifyUserAccount( // Verify authIdentifiers const accountIds = await Promise.all( - authIdentifiers.map(async (identifier) => identifyUser(identifier)) + authIdentifiers.map(async (identifier) => identifyUser(identifier, socialLibrary)) ); const deduplicateAccountIds = deduplicate(accountIds); diff --git a/packages/core/src/tenants/Libraries.ts b/packages/core/src/tenants/Libraries.ts index 95da5b6bb..4bde62de2 100644 --- a/packages/core/src/tenants/Libraries.ts +++ b/packages/core/src/tenants/Libraries.ts @@ -3,6 +3,7 @@ import { createHookLibrary } from '#src/libraries/hook.js'; import { createPhraseLibrary } from '#src/libraries/phrase.js'; import { createResourceLibrary } from '#src/libraries/resource.js'; import { createSignInExperienceLibrary } from '#src/libraries/sign-in-experience/index.js'; +import { createSocialLibrary } from '#src/libraries/social.js'; import { createUserLibrary } from '#src/libraries/user.js'; import type { ModelRouters } from '#src/model-routers/index.js'; @@ -15,6 +16,7 @@ export default class Libraries { phrases = createPhraseLibrary(this.queries); resources = createResourceLibrary(this.queries); hooks = createHookLibrary(this.queries, this.modelRouters); + socials = createSocialLibrary(this.queries, this.connectors); constructor(private readonly queries: Queries, private readonly modelRouters: ModelRouters) {} }