0
Fork 0
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:
Wang Sijie 2022-02-17 11:09:27 +08:00 committed by GitHub
parent 13f6b59ad4
commit 46dd8f3b69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 107 additions and 23 deletions

View file

@ -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());

View file

@ -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(

View file

@ -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(

View file

@ -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;
}

View file

@ -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

View 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
);
}
}
};
}

View file

@ -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.',
},

View file

@ -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 是否有效。',
},