From 5c7e20bfd4c451eb4ee5e73bba5bfa5bb3ff5f77 Mon Sep 17 00:00:00 2001 From: Darcy Ye Date: Wed, 22 Feb 2023 14:19:16 +0800 Subject: [PATCH] fix(core): should throw error when multiple connector factories have same id (#3170) --- packages/core/src/routes/connector.ts | 31 +++++++++---------- .../core/src/utils/connectors/factories.ts | 22 +++++++++++++ packages/phrases/src/locales/de/errors.ts | 2 ++ packages/phrases/src/locales/en/errors.ts | 2 ++ packages/phrases/src/locales/fr/errors.ts | 2 ++ packages/phrases/src/locales/ko/errors.ts | 2 ++ packages/phrases/src/locales/pt-br/errors.ts | 2 ++ packages/phrases/src/locales/pt-pt/errors.ts | 2 ++ packages/phrases/src/locales/tr-tr/errors.ts | 2 ++ packages/phrases/src/locales/zh-cn/errors.ts | 1 + 10 files changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/core/src/routes/connector.ts b/packages/core/src/routes/connector.ts index 79ed2482d..7522522d4 100644 --- a/packages/core/src/routes/connector.ts +++ b/packages/core/src/routes/connector.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-lines */ import { VerificationCodeType, validateConfig } from '@logto/connector-kit'; import { emailRegEx, phoneRegEx, buildIdGenerator } from '@logto/core-kit'; import type { ConnectorResponse, ConnectorFactoryResponse } from '@logto/schemas'; @@ -13,7 +12,7 @@ import assertThat from '#src/utils/assert-that.js'; import { loadConnectorFactories } from '#src/utils/connectors/factories.js'; import { buildRawConnector } from '#src/utils/connectors/index.js'; import { checkSocialConnectorTargetAndPlatformUniqueness } from '#src/utils/connectors/platform.js'; -import type { LogtoConnector } from '#src/utils/connectors/types.js'; +import type { ConnectorFactory, LogtoConnector } from '#src/utils/connectors/types.js'; import type { AuthedRouter, RouterInitArgs } from './types.js'; @@ -29,6 +28,13 @@ const transpileLogtoConnector = ({ }; }; +const transpileConnectorFactory = ({ + metadata, + type, +}: ConnectorFactory): ConnectorFactoryResponse => { + return { type, ...metadata }; +}; + const generateConnectorId = buildIdGenerator(12); export default function connectorRoutes( @@ -81,13 +87,9 @@ export default function connectorRoutes( router.get('/connector-factories', async (ctx, next) => { const connectorFactories = await loadConnectorFactories(); - const formatedFactories: ConnectorFactoryResponse[] = connectorFactories.map( - ({ metadata, type }) => ({ - type, - ...metadata, - }) + ctx.body = connectorFactories.map((connectorFactory) => + transpileConnectorFactory(connectorFactory) ); - ctx.body = formatedFactories; return next(); }); @@ -100,16 +102,11 @@ export default function connectorRoutes( params: { id }, } = ctx.guard; const connectorFactories = await loadConnectorFactories(); - const connectorFactory = connectorFactories.find((factory) => factory.metadata.id === id); + const connectorFactory = connectorFactories.find((factory) => factory.metadata.id === id); assertThat(connectorFactory, 'entity.not_found'); - const { metadata, type } = connectorFactory; - const response: ConnectorFactoryResponse = { - type, - ...metadata, - }; - ctx.body = response; + ctx.body = transpileConnectorFactory(connectorFactory); return next(); } @@ -147,6 +144,7 @@ export default function connectorRoutes( } = ctx.guard; const connectorFactories = await loadConnectorFactories(); + const connectorFactory = connectorFactories.find( ({ metadata: { id } }) => id === connectorId ); @@ -343,6 +341,7 @@ export default function connectorRoutes( const { connectorId } = await findConnectorById(id); const connectorFactories = await loadConnectorFactories(); + const connectorFactory = connectorFactories.find( ({ metadata }) => metadata.id === connectorId ); @@ -359,5 +358,3 @@ export default function connectorRoutes( } ); } -// TODO: @darcy refactor this file, exceed max-lines -/* eslint-enable max-lines */ diff --git a/packages/core/src/utils/connectors/factories.ts b/packages/core/src/utils/connectors/factories.ts index f8ad709df..825844279 100644 --- a/packages/core/src/utils/connectors/factories.ts +++ b/packages/core/src/utils/connectors/factories.ts @@ -5,19 +5,39 @@ import path from 'path'; import { connectorDirectory } from '@logto/cli/lib/constants.js'; import { getConnectorPackagesFromDirectory } from '@logto/cli/lib/utils.js'; import { findPackage } from '@logto/shared'; +import { deduplicate } from '@silverhand/essentials'; import chalk from 'chalk'; +import RequestError from '#src/errors/RequestError/index.js'; import type { ConnectorFactory } from '#src/utils/connectors/types.js'; import { notImplemented } from './consts.js'; import { parseMetadata, validateConnectorModule } from './index.js'; import { loadConnector } from './loader.js'; +const checkDuplicateConnectorFactoriesId = (connectorFactories: ConnectorFactory[]) => { + const connectorFactoryIds = connectorFactories.map(({ metadata }) => metadata.id); + const deduplicatedConnectorFactoryIds = deduplicate(connectorFactoryIds); + + if (connectorFactoryIds.length !== deduplicatedConnectorFactoryIds.length) { + const duplicatedConnectorFactoryIds = deduplicatedConnectorFactoryIds.filter( + (deduplicateId) => connectorFactoryIds.filter((id) => id === deduplicateId).length > 1 + ); + throw new RequestError({ + code: 'connector.more_than_one_connector_factory', + status: 422, + connectorIds: duplicatedConnectorFactoryIds.map((id) => `${id}`).join(', '), + }); + } +}; + // eslint-disable-next-line @silverhand/fp/no-let let cachedConnectorFactories: ConnectorFactory[] | undefined; export const loadConnectorFactories = async () => { if (cachedConnectorFactories) { + checkDuplicateConnectorFactoriesId(cachedConnectorFactories); + return cachedConnectorFactories; } @@ -65,5 +85,7 @@ export const loadConnectorFactories = async () => { (connectorFactory): connectorFactory is ConnectorFactory => connectorFactory !== undefined ); + checkDuplicateConnectorFactoriesId(cachedConnectorFactories); + return cachedConnectorFactories; }; diff --git a/packages/phrases/src/locales/de/errors.ts b/packages/phrases/src/locales/de/errors.ts index 0e5a556b8..b2492c441 100644 --- a/packages/phrases/src/locales/de/errors.ts +++ b/packages/phrases/src/locales/de/errors.ts @@ -113,6 +113,8 @@ const errors = { social_auth_code_invalid: 'Unable to get access token, please check authorization code.', more_than_one_sms: 'The number of SMS connectors is larger then 1.', more_than_one_email: 'The number of Email connectors is larger then 1.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: 'There is a connector in the DB that does not match the type.', not_found_with_connector_id: 'Can not find connector with given standard connector id.', multiple_instances_not_supported: diff --git a/packages/phrases/src/locales/en/errors.ts b/packages/phrases/src/locales/en/errors.ts index f03df08bf..3e78ba577 100644 --- a/packages/phrases/src/locales/en/errors.ts +++ b/packages/phrases/src/locales/en/errors.ts @@ -112,6 +112,8 @@ const errors = { social_auth_code_invalid: 'Unable to get access token, please check authorization code.', more_than_one_sms: 'The number of SMS connectors is larger then 1.', more_than_one_email: 'The number of Email connectors is larger then 1.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: 'There is a connector in the DB that does not match the type.', not_found_with_connector_id: 'Can not find connector with given standard connector id.', multiple_instances_not_supported: diff --git a/packages/phrases/src/locales/fr/errors.ts b/packages/phrases/src/locales/fr/errors.ts index 95bc6761d..b33cf2646 100644 --- a/packages/phrases/src/locales/fr/errors.ts +++ b/packages/phrases/src/locales/fr/errors.ts @@ -118,6 +118,8 @@ const errors = { "Impossible d'obtenir le jeton d'accès, veuillez vérifier le code d'autorisation.", more_than_one_sms: 'Le nombre de connecteurs SMS est supérieur à 1.', more_than_one_email: 'Le nombre de connecteurs Email est supérieur à 1.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: 'Il y a un connecteur dans la base de donnée qui ne correspond pas au type.', not_found_with_connector_id: 'Can not find connector with given standard connector id.', // UNTRANSLATED diff --git a/packages/phrases/src/locales/ko/errors.ts b/packages/phrases/src/locales/ko/errors.ts index 0d2ad1157..26072baf7 100644 --- a/packages/phrases/src/locales/ko/errors.ts +++ b/packages/phrases/src/locales/ko/errors.ts @@ -109,6 +109,8 @@ const errors = { social_auth_code_invalid: 'Access 토큰을 가져올 수 없어요. Authorization 코드를 확인해 주세요.', more_than_one_sms: 'SMS 서비스는 1개만 연동되어야 해요.', more_than_one_email: '이메일 서비스는 1개만 연동되어야 해요.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: '종류가 일치하지 않은 연동 서비스가 DB에 존재해요.', not_found_with_connector_id: '주어진 연동 ID로 연동 설정을 찾을 수 없어요.', multiple_instances_not_supported: '선택된 연동 기준으로 여러 인스턴스를 생성할 수 없어요.', diff --git a/packages/phrases/src/locales/pt-br/errors.ts b/packages/phrases/src/locales/pt-br/errors.ts index 953d0ef80..2ab8b3f1b 100644 --- a/packages/phrases/src/locales/pt-br/errors.ts +++ b/packages/phrases/src/locales/pt-br/errors.ts @@ -114,6 +114,8 @@ const errors = { 'Não foi possível obter o token de acesso, verifique o código de autorização.', more_than_one_sms: 'O número de conectores SMS é maior que 1.', more_than_one_email: 'O número de conectores de e-mail é maior que 1.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: 'Existe um conector no banco de dados que não corresponde ao tipo.', not_found_with_connector_id: 'Não é possível encontrar o conector com o ID de conector padrão fornecido.', diff --git a/packages/phrases/src/locales/pt-pt/errors.ts b/packages/phrases/src/locales/pt-pt/errors.ts index dfff359c0..205c4508b 100644 --- a/packages/phrases/src/locales/pt-pt/errors.ts +++ b/packages/phrases/src/locales/pt-pt/errors.ts @@ -114,6 +114,8 @@ const errors = { 'Não foi possível obter o token de acesso, verifique o código de autorização.', more_than_one_sms: 'O número de conectores SMS é maior que 1.', more_than_one_email: 'O número de conectores de e-mail é maior que 1.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: 'Há um conector no banco de dados que não corresponde ao tipo.', not_found_with_connector_id: 'Can not find connector with given standard connector id.', // UNTRANSLATED multiple_instances_not_supported: diff --git a/packages/phrases/src/locales/tr-tr/errors.ts b/packages/phrases/src/locales/tr-tr/errors.ts index 4f4823429..1b8304fed 100644 --- a/packages/phrases/src/locales/tr-tr/errors.ts +++ b/packages/phrases/src/locales/tr-tr/errors.ts @@ -113,6 +113,8 @@ const errors = { social_auth_code_invalid: 'Erişim tokenı alınamıyor, lütfen yetkilendirme kodunu kontrol edin.', more_than_one_sms: 'SMS bağlayıcılarının sayısı 1den fazla.', more_than_one_email: 'E-posta adresi bağlayıcılarının sayısı 1den fazla.', + more_than_one_connector_factory: + 'Found multiple connector factories (with id {{connectorIds}}), you may uninstall unnecessary ones.', // UNTRANSLATED db_connector_type_mismatch: 'Dbde türle eşleşmeyen bir bağlayıcı var.', not_found_with_connector_id: 'Can not find connector with given standard connector id.', // UNTRANSLATED multiple_instances_not_supported: diff --git a/packages/phrases/src/locales/zh-cn/errors.ts b/packages/phrases/src/locales/zh-cn/errors.ts index 13723848f..0ee9bf674 100644 --- a/packages/phrases/src/locales/zh-cn/errors.ts +++ b/packages/phrases/src/locales/zh-cn/errors.ts @@ -105,6 +105,7 @@ const errors = { social_auth_code_invalid: '无法获取 access_token,请检查授权 code 是否有效', more_than_one_sms: '同时存在超过 1 个短信连接器', more_than_one_email: '同时存在超过 1 个邮件连接器', + more_than_one_connector_factory: '找到多个连接器工厂(id 为 {{connectorIds}}),请删除多余项。', db_connector_type_mismatch: '数据库中存在一个类型不匹配的连接。', not_found_with_connector_id: '找不到所给 connector id 对应的连接器', multiple_instances_not_supported: '你选择的连接器不支持创建多实例。',