0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

fix(core): should throw error when multiple connector factories have same id (#3170)

This commit is contained in:
Darcy Ye 2023-02-22 14:19:16 +08:00 committed by GitHub
parent 52dfe57ed3
commit 5c7e20bfd4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 51 additions and 17 deletions

View file

@ -1,4 +1,3 @@
/* eslint-disable max-lines */
import { VerificationCodeType, validateConfig } from '@logto/connector-kit'; import { VerificationCodeType, validateConfig } from '@logto/connector-kit';
import { emailRegEx, phoneRegEx, buildIdGenerator } from '@logto/core-kit'; import { emailRegEx, phoneRegEx, buildIdGenerator } from '@logto/core-kit';
import type { ConnectorResponse, ConnectorFactoryResponse } from '@logto/schemas'; 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 { loadConnectorFactories } from '#src/utils/connectors/factories.js';
import { buildRawConnector } from '#src/utils/connectors/index.js'; import { buildRawConnector } from '#src/utils/connectors/index.js';
import { checkSocialConnectorTargetAndPlatformUniqueness } from '#src/utils/connectors/platform.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'; 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); const generateConnectorId = buildIdGenerator(12);
export default function connectorRoutes<T extends AuthedRouter>( export default function connectorRoutes<T extends AuthedRouter>(
@ -81,13 +87,9 @@ export default function connectorRoutes<T extends AuthedRouter>(
router.get('/connector-factories', async (ctx, next) => { router.get('/connector-factories', async (ctx, next) => {
const connectorFactories = await loadConnectorFactories(); const connectorFactories = await loadConnectorFactories();
const formatedFactories: ConnectorFactoryResponse[] = connectorFactories.map( ctx.body = connectorFactories.map((connectorFactory) =>
({ metadata, type }) => ({ transpileConnectorFactory(connectorFactory)
type,
...metadata,
})
); );
ctx.body = formatedFactories;
return next(); return next();
}); });
@ -100,16 +102,11 @@ export default function connectorRoutes<T extends AuthedRouter>(
params: { id }, params: { id },
} = ctx.guard; } = ctx.guard;
const connectorFactories = await loadConnectorFactories(); 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'); assertThat(connectorFactory, 'entity.not_found');
const { metadata, type } = connectorFactory; ctx.body = transpileConnectorFactory(connectorFactory);
const response: ConnectorFactoryResponse = {
type,
...metadata,
};
ctx.body = response;
return next(); return next();
} }
@ -147,6 +144,7 @@ export default function connectorRoutes<T extends AuthedRouter>(
} = ctx.guard; } = ctx.guard;
const connectorFactories = await loadConnectorFactories(); const connectorFactories = await loadConnectorFactories();
const connectorFactory = connectorFactories.find( const connectorFactory = connectorFactories.find(
({ metadata: { id } }) => id === connectorId ({ metadata: { id } }) => id === connectorId
); );
@ -343,6 +341,7 @@ export default function connectorRoutes<T extends AuthedRouter>(
const { connectorId } = await findConnectorById(id); const { connectorId } = await findConnectorById(id);
const connectorFactories = await loadConnectorFactories(); const connectorFactories = await loadConnectorFactories();
const connectorFactory = connectorFactories.find( const connectorFactory = connectorFactories.find(
({ metadata }) => metadata.id === connectorId ({ metadata }) => metadata.id === connectorId
); );
@ -359,5 +358,3 @@ export default function connectorRoutes<T extends AuthedRouter>(
} }
); );
} }
// TODO: @darcy refactor this file, exceed max-lines
/* eslint-enable max-lines */

View file

@ -5,19 +5,39 @@ import path from 'path';
import { connectorDirectory } from '@logto/cli/lib/constants.js'; import { connectorDirectory } from '@logto/cli/lib/constants.js';
import { getConnectorPackagesFromDirectory } from '@logto/cli/lib/utils.js'; import { getConnectorPackagesFromDirectory } from '@logto/cli/lib/utils.js';
import { findPackage } from '@logto/shared'; import { findPackage } from '@logto/shared';
import { deduplicate } from '@silverhand/essentials';
import chalk from 'chalk'; import chalk from 'chalk';
import RequestError from '#src/errors/RequestError/index.js';
import type { ConnectorFactory } from '#src/utils/connectors/types.js'; import type { ConnectorFactory } from '#src/utils/connectors/types.js';
import { notImplemented } from './consts.js'; import { notImplemented } from './consts.js';
import { parseMetadata, validateConnectorModule } from './index.js'; import { parseMetadata, validateConnectorModule } from './index.js';
import { loadConnector } from './loader.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 // eslint-disable-next-line @silverhand/fp/no-let
let cachedConnectorFactories: ConnectorFactory[] | undefined; let cachedConnectorFactories: ConnectorFactory[] | undefined;
export const loadConnectorFactories = async () => { export const loadConnectorFactories = async () => {
if (cachedConnectorFactories) { if (cachedConnectorFactories) {
checkDuplicateConnectorFactoriesId(cachedConnectorFactories);
return cachedConnectorFactories; return cachedConnectorFactories;
} }
@ -65,5 +85,7 @@ export const loadConnectorFactories = async () => {
(connectorFactory): connectorFactory is ConnectorFactory => connectorFactory !== undefined (connectorFactory): connectorFactory is ConnectorFactory => connectorFactory !== undefined
); );
checkDuplicateConnectorFactoriesId(cachedConnectorFactories);
return cachedConnectorFactories; return cachedConnectorFactories;
}; };

View file

@ -113,6 +113,8 @@ const errors = {
social_auth_code_invalid: 'Unable to get access token, please check authorization code.', 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_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_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.', 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.', not_found_with_connector_id: 'Can not find connector with given standard connector id.',
multiple_instances_not_supported: multiple_instances_not_supported:

View file

@ -112,6 +112,8 @@ const errors = {
social_auth_code_invalid: 'Unable to get access token, please check authorization code.', 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_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_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.', 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.', not_found_with_connector_id: 'Can not find connector with given standard connector id.',
multiple_instances_not_supported: multiple_instances_not_supported:

View file

@ -118,6 +118,8 @@ const errors = {
"Impossible d'obtenir le jeton d'accès, veuillez vérifier le code d'autorisation.", "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_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_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: db_connector_type_mismatch:
'Il y a un connecteur dans la base de donnée qui ne correspond pas au type.', '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 not_found_with_connector_id: 'Can not find connector with given standard connector id.', // UNTRANSLATED

View file

@ -109,6 +109,8 @@ const errors = {
social_auth_code_invalid: 'Access 토큰을 가져올 수 없어요. Authorization 코드를 확인해 주세요.', social_auth_code_invalid: 'Access 토큰을 가져올 수 없어요. Authorization 코드를 확인해 주세요.',
more_than_one_sms: 'SMS 서비스는 1개만 연동되어야 해요.', more_than_one_sms: 'SMS 서비스는 1개만 연동되어야 해요.',
more_than_one_email: '이메일 서비스는 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에 존재해요.', db_connector_type_mismatch: '종류가 일치하지 않은 연동 서비스가 DB에 존재해요.',
not_found_with_connector_id: '주어진 연동 ID로 연동 설정을 찾을 수 없어요.', not_found_with_connector_id: '주어진 연동 ID로 연동 설정을 찾을 수 없어요.',
multiple_instances_not_supported: '선택된 연동 기준으로 여러 인스턴스를 생성할 수 없어요.', multiple_instances_not_supported: '선택된 연동 기준으로 여러 인스턴스를 생성할 수 없어요.',

View file

@ -114,6 +114,8 @@ const errors = {
'Não foi possível obter o token de acesso, verifique o código de autorização.', '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_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_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.', db_connector_type_mismatch: 'Existe um conector no banco de dados que não corresponde ao tipo.',
not_found_with_connector_id: not_found_with_connector_id:
'Não é possível encontrar o conector com o ID de conector padrão fornecido.', 'Não é possível encontrar o conector com o ID de conector padrão fornecido.',

View file

@ -114,6 +114,8 @@ const errors = {
'Não foi possível obter o token de acesso, verifique o código de autorização.', '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_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_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.', 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 not_found_with_connector_id: 'Can not find connector with given standard connector id.', // UNTRANSLATED
multiple_instances_not_supported: multiple_instances_not_supported:

View file

@ -113,6 +113,8 @@ const errors = {
social_auth_code_invalid: 'Erişim tokenı alınamıyor, lütfen yetkilendirme kodunu kontrol edin.', 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_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_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.', 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 not_found_with_connector_id: 'Can not find connector with given standard connector id.', // UNTRANSLATED
multiple_instances_not_supported: multiple_instances_not_supported:

View file

@ -105,6 +105,7 @@ const errors = {
social_auth_code_invalid: '无法获取 access_token请检查授权 code 是否有效', social_auth_code_invalid: '无法获取 access_token请检查授权 code 是否有效',
more_than_one_sms: '同时存在超过 1 个短信连接器', more_than_one_sms: '同时存在超过 1 个短信连接器',
more_than_one_email: '同时存在超过 1 个邮件连接器', more_than_one_email: '同时存在超过 1 个邮件连接器',
more_than_one_connector_factory: '找到多个连接器工厂id 为 {{connectorIds}}),请删除多余项。',
db_connector_type_mismatch: '数据库中存在一个类型不匹配的连接。', db_connector_type_mismatch: '数据库中存在一个类型不匹配的连接。',
not_found_with_connector_id: '找不到所给 connector id 对应的连接器', not_found_with_connector_id: '找不到所给 connector id 对应的连接器',
multiple_instances_not_supported: '你选择的连接器不支持创建多实例。', multiple_instances_not_supported: '你选择的连接器不支持创建多实例。',