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:
parent
52dfe57ed3
commit
5c7e20bfd4
10 changed files with 51 additions and 17 deletions
|
@ -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 */
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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: '선택된 연동 기준으로 여러 인스턴스를 생성할 수 없어요.',
|
||||||
|
|
|
@ -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.',
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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: '你选择的连接器不支持创建多实例。',
|
||||||
|
|
Loading…
Reference in a new issue