mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
chore: connector error (#242)
This commit is contained in:
parent
13f6b59ad4
commit
46dd8f3b69
8 changed files with 107 additions and 23 deletions
|
@ -5,6 +5,7 @@ import Koa from 'koa';
|
|||
import koaLogger from 'koa-logger';
|
||||
|
||||
import { port } from '@/env/consts';
|
||||
import koaConnectorErrorHandler from '@/middleware/koa-connector-error-handle';
|
||||
import koaErrorHandler from '@/middleware/koa-error-handler';
|
||||
import koaI18next from '@/middleware/koa-i18next';
|
||||
import koaOIDCErrorHandler from '@/middleware/koa-oidc-error-handler';
|
||||
|
@ -18,6 +19,7 @@ export default async function initApp(app: Koa): Promise<void> {
|
|||
app.use(koaErrorHandler());
|
||||
app.use(koaOIDCErrorHandler());
|
||||
app.use(koaSlonikErrorHandler());
|
||||
app.use(koaConnectorErrorHandler());
|
||||
|
||||
// TODO move to specific router (LOG-454)
|
||||
app.use(koaUserLog());
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
ConnectorConfigError,
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
ConnectorMetadata,
|
||||
ConnectorType,
|
||||
EmailSendMessageFunction,
|
||||
|
@ -46,13 +46,13 @@ const configGuard = z.object({
|
|||
|
||||
export const validateConfig: ValidateConfig = async (config: unknown) => {
|
||||
if (!config) {
|
||||
throw new ConnectorConfigError('Missing config');
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, 'Missing config');
|
||||
}
|
||||
|
||||
const result = configGuard.safeParse(config);
|
||||
|
||||
if (!result.success) {
|
||||
throw new ConnectorConfigError(result.error.message);
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, result.error.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -65,7 +65,10 @@ export const sendMessage: EmailSendMessageFunction = async (address, type, data)
|
|||
const template = templates.find((template) => template.usageType === type);
|
||||
|
||||
if (!template) {
|
||||
throw new ConnectorError(`Cannot find template for type: ${type}`);
|
||||
throw new ConnectorError(
|
||||
ConnectorErrorCodes.TemplateNotFound,
|
||||
`Cannot find template for type: ${type}`
|
||||
);
|
||||
}
|
||||
|
||||
return singleSendMail(
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
import {
|
||||
ConnectorConfigError,
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
ConnectorMetadata,
|
||||
ConnectorType,
|
||||
SmsSendMessageFunction,
|
||||
|
@ -70,13 +70,13 @@ const configGuard = z.object({
|
|||
|
||||
export const validateConfig: ValidateConfig = async (config: unknown) => {
|
||||
if (!config) {
|
||||
throw new ConnectorConfigError('Missing config');
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, 'Missing config');
|
||||
}
|
||||
|
||||
const result = configGuard.safeParse(config);
|
||||
|
||||
if (!result.success) {
|
||||
throw new ConnectorConfigError(result.error.message);
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, result.error.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -91,7 +91,10 @@ export const sendMessage: SmsSendMessageFunction = async (phone, type, { code })
|
|||
);
|
||||
|
||||
if (!template) {
|
||||
throw new ConnectorError(`Cannot find template code: ${templateCode}`);
|
||||
throw new ConnectorError(
|
||||
ConnectorErrorCodes.TemplateNotFound,
|
||||
`Cannot find template code: ${templateCode}`
|
||||
);
|
||||
}
|
||||
|
||||
return sendSms(
|
||||
|
|
|
@ -2,16 +2,15 @@ import got, { RequestError as GotRequestError } from 'got';
|
|||
import { stringify } from 'query-string';
|
||||
import { z } from 'zod';
|
||||
|
||||
import RequestError from '@/errors/RequestError';
|
||||
|
||||
import {
|
||||
ConnectorConfigError,
|
||||
ConnectorMetadata,
|
||||
GetAccessToken,
|
||||
GetAuthorizationUri,
|
||||
ValidateConfig,
|
||||
GetUserInfo,
|
||||
ConnectorType,
|
||||
ConnectorError,
|
||||
ConnectorErrorCodes,
|
||||
} from '../types';
|
||||
import { getConnectorConfig } from '../utilities';
|
||||
import { authorizationEndpoint, accessTokenEndpoint, scope, userInfoEndpoint } from './constant';
|
||||
|
@ -39,13 +38,13 @@ type GithubConfig = z.infer<typeof githubConfigGuard>;
|
|||
|
||||
export const validateConfig: ValidateConfig = async (config: unknown) => {
|
||||
if (!config) {
|
||||
throw new ConnectorConfigError('Missing config');
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, 'Missing config');
|
||||
}
|
||||
|
||||
const result = githubConfigGuard.safeParse(config);
|
||||
|
||||
if (!result.success) {
|
||||
throw new ConnectorConfigError(result.error.message);
|
||||
throw new ConnectorError(ConnectorErrorCodes.InvalidConfig, result.error.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -82,10 +81,7 @@ export const getAccessToken: GetAccessToken = async (code) => {
|
|||
.json<AccessTokenResponse>();
|
||||
|
||||
if (!accessToken) {
|
||||
throw new RequestError({
|
||||
code: 'connector.oauth_code_invalid',
|
||||
status: 401,
|
||||
});
|
||||
throw new ConnectorError(ConnectorErrorCodes.SocialAuthCodeInvalid);
|
||||
}
|
||||
|
||||
return accessToken;
|
||||
|
@ -121,10 +117,7 @@ export const getUserInfo: GetUserInfo = async (accessToken: string) => {
|
|||
};
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof GotRequestError && error.response?.statusCode === 401) {
|
||||
throw new RequestError({
|
||||
code: 'connector.access_token_invalid',
|
||||
status: 401,
|
||||
});
|
||||
throw new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
|
|
@ -67,9 +67,21 @@ export type SmsSendMessageFunction<T = unknown> = (
|
|||
|
||||
export type TemplateType = PasscodeType | 'Test';
|
||||
|
||||
export class ConnectorError extends Error {}
|
||||
export enum ConnectorErrorCodes {
|
||||
General,
|
||||
InvalidConfig,
|
||||
TemplateNotFound,
|
||||
SocialAuthCodeInvalid,
|
||||
SocialAccessTokenInvalid,
|
||||
}
|
||||
export class ConnectorError extends Error {
|
||||
public code: ConnectorErrorCodes;
|
||||
|
||||
export class ConnectorConfigError extends ConnectorError {}
|
||||
constructor(code: ConnectorErrorCodes, message?: string) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
export type ValidateConfig<T extends ConnectorConfig = ConnectorConfig> = (
|
||||
config: T
|
||||
|
|
65
packages/core/src/middleware/koa-connector-error-handle.ts
Normal file
65
packages/core/src/middleware/koa-connector-error-handle.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { Middleware } from 'koa';
|
||||
|
||||
import { ConnectorError, ConnectorErrorCodes } from '@/connectors/types';
|
||||
import RequestError from '@/errors/RequestError';
|
||||
|
||||
export default function koaConnectorErrorHandler<StateT, ContextT>(): Middleware<StateT, ContextT> {
|
||||
return async (ctx, next) => {
|
||||
try {
|
||||
await next();
|
||||
} catch (error: unknown) {
|
||||
if (!(error instanceof ConnectorError)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const { code, message } = error;
|
||||
|
||||
// Original OIDCProvider Error description and details are provided in the data field
|
||||
const data = { message };
|
||||
|
||||
switch (code) {
|
||||
case ConnectorErrorCodes.InvalidConfig:
|
||||
throw new RequestError(
|
||||
{
|
||||
code: 'connector.invalid_config',
|
||||
status: 500,
|
||||
},
|
||||
data
|
||||
);
|
||||
case ConnectorErrorCodes.SocialAccessTokenInvalid:
|
||||
throw new RequestError(
|
||||
{
|
||||
code: 'connector.access_token_invalid',
|
||||
status: 401,
|
||||
},
|
||||
data
|
||||
);
|
||||
case ConnectorErrorCodes.SocialAuthCodeInvalid:
|
||||
throw new RequestError(
|
||||
{
|
||||
code: 'connector.oauth_code_invalid',
|
||||
status: 401,
|
||||
},
|
||||
data
|
||||
);
|
||||
case ConnectorErrorCodes.TemplateNotFound:
|
||||
throw new RequestError(
|
||||
{
|
||||
code: 'connector.template_not_found',
|
||||
status: 500,
|
||||
},
|
||||
data
|
||||
);
|
||||
|
||||
default:
|
||||
throw new RequestError(
|
||||
{
|
||||
code: 'connector.general',
|
||||
status: 500,
|
||||
},
|
||||
data
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -67,8 +67,11 @@ const errors = {
|
|||
connector_id_mismatch: 'The connectorId is mismatched with session record.',
|
||||
},
|
||||
connector: {
|
||||
general: 'An unexpected error occured in connector.',
|
||||
not_found: 'Cannot find any available connector for type: {{type}}.',
|
||||
not_enabled: 'The connector is not enabled.',
|
||||
invalid_config: "The connector's config is invalid.",
|
||||
template_not_found: 'Unable to find correct template in connector config.',
|
||||
access_token_invalid: "Connector's access token is invalid.",
|
||||
oauth_code_invalid: 'Unable to get access token, please check authorization code.',
|
||||
},
|
||||
|
|
|
@ -68,8 +68,11 @@ const errors = {
|
|||
connector_id_mismatch: '传入的 connectorId 与 session 中保存的记录不一致。',
|
||||
},
|
||||
connector: {
|
||||
general: 'Connector 发生未知错误。',
|
||||
not_found: '找不到可用的 {{type}} 类型的连接器。',
|
||||
not_enabled: '连接器尚未启用。',
|
||||
invalid_config: 'Connector 配置错误。',
|
||||
template_not_found: '无法从 connector 配置中找到对应的模板。',
|
||||
access_token_invalid: '当前连接器的 access_token 无效。',
|
||||
oauth_code_invalid: '无法获取 access_token,请检查授权 code 是否有效。',
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue