0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-17 22:04:19 -05:00

refactor(core): refactor createSocialAuthorizationUrl and verifySocialIdentity (#2707)

Co-authored-by: simeng-li <simeng@silverhand.io>
This commit is contained in:
Darcy Ye 2022-12-26 10:23:40 +08:00 committed by GitHub
parent 1b709db854
commit 8c5ccac59f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 34 deletions

View file

@ -1,4 +1,3 @@
import type { ConnectorSession } from '@logto/connector-kit';
import type { LogtoErrorCode } from '@logto/phrases';
import { Event, eventGuard, identifierPayloadGuard, profileGuard } from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
@ -15,7 +14,6 @@ import type { AnonymousRouter } from '../types.js';
import submitInteraction from './actions/submit-interaction.js';
import { sendPasscodePayloadGuard, socialAuthorizationUrlPayloadGuard } from './types/guard.js';
import {
assignConnectorSessionResult,
getInteractionStorage,
storeInteractionResult,
mergeIdentifiers,
@ -236,11 +234,9 @@ export default function interactionRoutes<T extends AnonymousRouter>(
// Check interaction exists
await getInteractionStorage(ctx, provider);
const redirectTo = await createSocialAuthorizationUrl(
ctx.guard.body,
async (connectorStorage: ConnectorSession) =>
assignConnectorSessionResult(ctx, provider, connectorStorage)
);
const { body: payload } = ctx.guard;
const redirectTo = await createSocialAuthorizationUrl(ctx, provider, payload);
ctx.body = { redirectTo };

View file

@ -1,7 +1,9 @@
import { ConnectorType } from '@logto/connector-kit';
import { mockEsm } from '@logto/shared/esm';
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';
const { jest } = import.meta;
@ -24,16 +26,13 @@ const log = createMockLogContext();
describe('social-verification', () => {
it('verifySocialIdentity', async () => {
const getSession = jest.fn();
const provider = createMockProvider();
const ctx = { ...createMockContext(), ...log };
const connectorId = 'connector';
const connectorData = { authCode: 'code' };
const userInfo = await verifySocialIdentity(
{ connectorId, connectorData },
log.createLog,
getSession
);
const userInfo = await verifySocialIdentity({ connectorId, connectorData }, ctx, provider);
expect(getUserInfoByAuthCode).toBeCalledWith(connectorId, connectorData, getSession);
expect(getUserInfoByAuthCode).toBeCalledWith(connectorId, connectorData, expect.anything());
expect(userInfo).toEqual({ id: 'foo' });
});
});

View file

@ -1,18 +1,25 @@
import type { GetSession, SetSession } from '@logto/connector-kit';
import type { ConnectorSession } from '@logto/connector-kit';
import type { SocialConnectorPayload } from '@logto/schemas';
import { ConnectorType } from '@logto/schemas';
import type { Context } from 'koa';
import type { Provider } from 'oidc-provider';
import { getLogtoConnectorById } from '#src/connectors/index.js';
import type { SocialUserInfo } from '#src/connectors/types.js';
import { getUserInfoByAuthCode } from '#src/libraries/social.js';
import type { LogContext } from '#src/middleware/koa-audit-log.js';
import {
getConnectorSessionResult,
assignConnectorSessionResult,
} from '#src/routes/interaction/utils/interaction.js';
import assertThat from '#src/utils/assert-that.js';
import type { SocialAuthorizationUrlPayload } from '../types/index.js';
export const createSocialAuthorizationUrl = async (
payload: SocialAuthorizationUrlPayload,
setConnectorSession?: SetSession
ctx: Context,
provider: Provider,
payload: SocialAuthorizationUrlPayload
) => {
const { connectorId, state, redirectUri } = payload;
assertThat(state && redirectUri, 'session.insufficient_info');
@ -21,18 +28,26 @@ export const createSocialAuthorizationUrl = async (
assertThat(connector.type === ConnectorType.Social, 'connector.unexpected_type');
return connector.getAuthorizationUri({ state, redirectUri }, setConnectorSession);
return connector.getAuthorizationUri(
{ state, redirectUri },
async (connectorStorage: ConnectorSession) =>
assignConnectorSessionResult(ctx, provider, connectorStorage)
);
};
export const verifySocialIdentity = async (
{ connectorId, connectorData }: SocialConnectorPayload,
createLog: LogContext['createLog'],
getSession?: GetSession
ctx: Context,
provider: Provider
): Promise<SocialUserInfo> => {
// eslint-disable-next-line prefer-destructuring, @typescript-eslint/no-unsafe-assignment
const createLog: LogContext['createLog'] = ctx.createLog;
const log = createLog('Interaction.SignIn.Identifier.Social.Submit');
log.append({ connectorId, connectorData });
const userInfo = await getUserInfoByAuthCode(connectorId, connectorData, getSession);
const userInfo = await getUserInfoByAuthCode(connectorId, connectorData, async () =>
getConnectorSessionResult(ctx, provider)
);
log.append(userInfo);

View file

@ -154,18 +154,15 @@ describe('identifier verification', () => {
it('social', async () => {
const identifier = { connectorId: 'logto', connectorData: {} };
const provider = createMockProvider();
const result = await identifierPayloadVerification(
baseCtx,
createMockProvider(),
provider,
identifier,
interactionStorage
);
expect(verifySocialIdentity).toBeCalledWith(
identifier,
logContext.createLog,
expect.anything()
);
expect(verifySocialIdentity).toBeCalledWith(identifier, baseCtx, provider);
expect(findUserByIdentifier).not.toBeCalled();
expect(result).toEqual({

View file

@ -1,4 +1,3 @@
import type { GetSession } from '@logto/connector-kit';
import type {
Event,
IdentifierPayload,
@ -10,7 +9,6 @@ import type { Provider } from 'oidc-provider';
import RequestError from '#src/errors/RequestError/index.js';
import { verifyUserPassword } from '#src/libraries/user.js';
import { getConnectorSessionResult } from '#src/routes/interaction/utils/interaction.js';
import assertThat from '#src/utils/assert-that.js';
import type {
@ -60,9 +58,9 @@ const verifyPasscodeIdentifier = async (
const verifySocialIdentifier = async (
identifier: SocialConnectorPayload,
ctx: Context,
getSession?: GetSession
provider: Provider
): Promise<SocialIdentifier> => {
const userInfo = await verifySocialIdentity(identifier, ctx.createLog, getSession);
const userInfo = await verifySocialIdentity(identifier, ctx, provider);
return { key: 'social', connectorId: identifier.connectorId, userInfo };
};
@ -104,9 +102,7 @@ export default async function identifierPayloadVerification(
}
if (isSocialIdentifier(identifierPayload)) {
return verifySocialIdentifier(identifierPayload, ctx, async () =>
getConnectorSessionResult(ctx, provider)
);
return verifySocialIdentifier(identifierPayload, ctx, provider);
}
// Sign-In with social verified email or phone