Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions packages/global/common/error/code/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ export enum UserErrEnum {
userExist = 'userExist',
unAuthRole = 'unAuthRole',
account_psw_error = 'account_psw_error',
unAuthSso = 'unAuthSso'
unAuthSso = 'unAuthSso',
invalidVerificationCode = 'invalidVerificationCode',
sendVerificationCodeTooFrequently = 'sendVerificationCodeTooFrequently',
verifyCodeTooFrequently = 'verifyCodeTooFrequently'
}
const errList = [
{
Expand All @@ -24,6 +27,21 @@ const errList = [
{
statusText: UserErrEnum.unAuthSso,
message: i18nT('user:sso_auth_failed')
},
{
statusText: UserErrEnum.invalidVerificationCode,
message: i18nT('common:error.code_error'),
httpStatus: 400
},
{
statusText: UserErrEnum.sendVerificationCodeTooFrequently,
message: i18nT('common:error.send_auth_code_too_frequently'),
httpStatus: 429
},
{
statusText: UserErrEnum.verifyCodeTooFrequently,
message: i18nT('common:error.verify_code_too_frequently'),
httpStatus: 429
}
];
export default errList.reduce((acc, cur, index) => {
Expand All @@ -33,7 +51,8 @@ export default errList.reduce((acc, cur, index) => {
code: 503000 + index,
statusText: cur.statusText,
message: cur.message,
data: null
data: null,
...(cur.httpStatus !== undefined ? { httpStatus: cur.httpStatus } : {})
}
};
}, {} as ErrType<`${UserErrEnum}`>);
1 change: 0 additions & 1 deletion packages/global/common/system/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ export type FastGPTFeConfigsType = {
login_method?: FastGPTRegisterMethodType[]; // Attention: login method is different with oauth
find_password_method?: FastGPTRegisterMethodType[];
bind_notification_method?: FastGPTRegisterMethodType[];
googleClientVerKey?: string;
/**
* @deprecated MCP SSE 代理地址已迁移到环境变量 SSE_MCP_SERVER_PROXY_ENDPOINT。
* 运行时配置以环境变量为准,admin 不再支持写入该字段。
Expand Down
3 changes: 2 additions & 1 deletion packages/global/openapi/support/user/account/password/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { z } from 'zod';
import { LanguageSchema } from '../../../../../common/i18n/type';
import { AccountContactUsernameSchema } from '../../../../../support/user/account/verification/type';

// ===== Update password by old password =====
export const UpdatePasswordByOldBodySchema = z
Expand Down Expand Up @@ -54,7 +55,7 @@ export type ResetExpiredPswResponseType = z.infer<typeof ResetExpiredPswResponse

// ===== Find Password (update by code) =====
export const UpdatePasswordByCodeBodySchema = z.object({
username: z.string().trim().min(1).meta({ description: '用户名' }),
username: AccountContactUsernameSchema.meta({ description: '用户名(邮箱或手机号)' }),
code: z.string().meta({ description: '验证码' }),
password: z.string().trim().min(1).meta({ description: '新密码' }),
tmbId: z.string().optional().meta({ description: '团队成员 ID(可选)' }),
Expand Down
25 changes: 25 additions & 0 deletions packages/global/openapi/support/user/account/password/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,33 @@ import {
ResetExpiredPswResponseSchema,
UpdatePasswordByCodeBodySchema
} from './api';
import { SendAuthCodeResponseSchema, SendForgetPasswordAuthCodeBodySchema } from '../../inform/api';

export const PasswordPath: OpenAPIPath = {
'/proApi/support/user/account/password/sendAuthCode': {
post: {
summary: '发送找回密码验证码',
description: '发送找回密码使用的邮箱或手机号验证码',
tags: [DevApiTagsMap.userLogin],
requestBody: {
content: {
'application/json': {
schema: SendForgetPasswordAuthCodeBodySchema
}
}
},
responses: {
200: {
description: '验证码发送成功',
content: {
'application/json': {
schema: SendAuthCodeResponseSchema
}
}
}
}
}
},
'/support/user/account/updatePasswordByOld': {
post: {
summary: '通过旧密码修改密码',
Expand Down
3 changes: 2 additions & 1 deletion packages/global/openapi/support/user/account/register/api.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { z } from 'zod';
import { TrackRegisterParamsSchema } from '../../../../../support/marketing/type';
import { LanguageSchema } from '../../../../../common/i18n/type';
import { AccountContactUsernameSchema } from '../../../../../support/user/account/verification/type';

// ===== Register by email or phone =====
export const AccountRegisterBodySchema = TrackRegisterParamsSchema.extend({
username: z.string().meta({ description: '用户名(邮箱或手机号)' }),
username: AccountContactUsernameSchema.meta({ description: '用户名(邮箱或手机号)' }),
code: z.string().meta({ description: '验证码' }),
password: z.string().meta({ description: '密码(已加密)' }),
language: LanguageSchema.optional().meta({ description: '语言' })
Expand Down
25 changes: 25 additions & 0 deletions packages/global/openapi/support/user/account/register/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
import type { OpenAPIPath } from '../../../../type';
import { DevApiTagsMap } from '../../../../tag';
import { AccountRegisterBodySchema } from './api';
import { SendAuthCodeResponseSchema, SendRegisterAuthCodeBodySchema } from '../../inform/api';

export const RegisterPath: OpenAPIPath = {
'/proApi/support/user/account/register/sendAuthCode': {
post: {
summary: '发送注册验证码',
description: '发送注册使用的邮箱或手机号验证码',
tags: [DevApiTagsMap.userLogin],
requestBody: {
content: {
'application/json': {
schema: SendRegisterAuthCodeBodySchema
}
}
},
responses: {
200: {
description: '验证码发送成功',
content: {
'application/json': {
schema: SendAuthCodeResponseSchema
}
}
}
}
}
},
'/support/user/account/register/emailAndPhone': {
post: {
summary: '邮箱/手机号注册',
Expand Down
64 changes: 64 additions & 0 deletions packages/global/openapi/support/user/inform/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { z } from 'zod';
import { LanguageSchema } from '../../../../common/i18n/type';
import { UserAuthTypeEnum } from '../../../../support/user/auth/constants';
import { AccountContactUsernameSchema } from '../../../../support/user/account/verification/type';

const SendAuthCodeBodySchema = z
.object({
username: AccountContactUsernameSchema.meta({
description: '接收验证码的邮箱或手机号',
example: 'user@example.com'
}),
type: z.enum(UserAuthTypeEnum).meta({
description: '验证码类型',
example: UserAuthTypeEnum.register
}),
captcha: z.string().min(1).max(64).meta({
description: '图片验证码答案',
example: 'A1B2C3'
}),
lang: LanguageSchema.meta({
description: '验证码消息语言',
example: 'zh-CN'
})
})
.strict();
export type SendAuthCodeBodyType = z.infer<typeof SendAuthCodeBodySchema>;

/** 注册验证码接口,purpose 由后端固定为 register。 */
export const SendRegisterAuthCodeBodySchema = SendAuthCodeBodySchema.extend({
type: z.literal(UserAuthTypeEnum.register).meta({
description: '验证码类型',
example: UserAuthTypeEnum.register
})
}).strict();
export type SendRegisterAuthCodeBodyType = z.infer<typeof SendRegisterAuthCodeBodySchema>;

/** 找回密码验证码接口,purpose 由后端固定为 forgetPassword。 */
export const SendForgetPasswordAuthCodeBodySchema = SendAuthCodeBodySchema.extend({
type: z.literal(UserAuthTypeEnum.findPassword).meta({
description: '验证码类型',
example: UserAuthTypeEnum.findPassword
})
}).strict();
export type SendForgetPasswordAuthCodeBodyType = z.infer<
typeof SendForgetPasswordAuthCodeBodySchema
>;

/** 绑定通知账号验证码接口,purpose 由后端固定为 bindNotification。 */
export const SendBindNotificationAuthCodeBodySchema = SendAuthCodeBodySchema.extend({
type: z.literal(UserAuthTypeEnum.bindNotification).meta({
description: '验证码类型',
example: UserAuthTypeEnum.bindNotification
})
}).strict();
export type SendBindNotificationAuthCodeBodyType = z.infer<
typeof SendBindNotificationAuthCodeBodySchema
>;

export const SendAuthCodeResponseSchema = z
.object({
message: z.string().meta({ description: '发送结果说明', example: '发送验证码成功' })
})
.strict();
export type SendAuthCodeResponseType = z.infer<typeof SendAuthCodeResponseSchema>;
25 changes: 25 additions & 0 deletions packages/global/openapi/support/user/inform/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,33 @@ import {
ActivityAdResponseSchema
} from '../../../admin/support/user/inform/api';
import { DevApiTagsMap } from '../../../tag';
import { SendAuthCodeResponseSchema, SendBindNotificationAuthCodeBodySchema } from './api';

export const UserInformPath: OpenAPIPath = {
'/proApi/support/user/inform/sendAuthCode': {
post: {
summary: '发送绑定通知验证码',
description: '发送绑定通知账号使用的邮箱/短信验证码',
tags: [DevApiTagsMap.userInform],
requestBody: {
content: {
'application/json': {
schema: SendBindNotificationAuthCodeBodySchema
}
}
},
responses: {
200: {
description: '验证码发送成功',
content: {
'application/json': {
schema: SendAuthCodeResponseSchema
}
}
}
}
}
},
'/proApi/support/user/inform/getSystemMsgModal': {
get: {
summary: '获取系统弹窗内容',
Expand Down
8 changes: 8 additions & 0 deletions packages/global/support/user/account/verification/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { z } from 'zod';

export const AccountEmailUsernameSchema = z.email().max(254);
export const AccountPhoneUsernameSchema = z.string().regex(/^1[3456789]\d{9}$/);
export const AccountContactUsernameSchema = z.union([
AccountEmailUsernameSchema,
AccountPhoneUsernameSchema
]);
9 changes: 0 additions & 9 deletions packages/global/support/user/auth/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,3 @@ export enum UserAuthTypeEnum {
captcha = 'captcha',
login = 'login'
}

export const userAuthTypeMap = {
[UserAuthTypeEnum.register]: 'register',
[UserAuthTypeEnum.findPassword]: 'findPassword',
[UserAuthTypeEnum.wxLogin]: 'wxLogin',
[UserAuthTypeEnum.bindNotification]: 'bindNotification',
[UserAuthTypeEnum.captcha]: 'captcha',
[UserAuthTypeEnum.login]: 'login'
};
10 changes: 0 additions & 10 deletions packages/global/support/user/auth/type.ts

This file was deleted.

11 changes: 7 additions & 4 deletions packages/service/common/http/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,14 +167,17 @@ export const createApiEntry = <
});
}

span.setAttribute('http.response.status_code', 500);
setSpanError(span, error);

return jsonRes(res, {
const response = jsonRes(res, {
code: 500,
error,
url: req.url
});
span.setAttribute('http.response.status_code', res.statusCode);
if (res.statusCode >= 500) {
setSpanError(span, error);
}

return response;
}
}
)
Expand Down
18 changes: 18 additions & 0 deletions packages/service/common/response/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ function resolveHttpStatusForApiError(
const { code: propsCode = 200, error } = props;
const bc = processedError.code;

const explicitErrorStatus = error?.httpStatus;
if (
typeof explicitErrorStatus === 'number' &&
explicitErrorStatus >= 400 &&
explicitErrorStatus <= 599
) {
return explicitErrorStatus;
}

if (typeof bc === 'number' && bc >= 400 && bc <= 499) {
return bc;
}
Expand All @@ -57,6 +66,15 @@ function resolveHttpStatusForApiError(
}

const raw = typeof error === 'string' ? error : error?.message;
const configuredHttpStatus = ERROR_RESPONSE[raw]?.httpStatus;
if (
typeof configuredHttpStatus === 'number' &&
configuredHttpStatus >= 400 &&
configuredHttpStatus <= 599
) {
return configuredHttpStatus;
}

if (raw === 'EntityTooLarge') {
return 413;
}
Expand Down
8 changes: 7 additions & 1 deletion packages/service/support/permission/auth/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import { authOpenApiKey } from '../../../support/openapi/auth';
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
import { serviceEnv } from '../../../env';

/** 复用 service 包内的 Cookie 解析实现,供跨 workspace 的服务端模块使用。 */
export const parseCookie = (value?: string) => Cookie.parse(value || '');

/** 复用 service 包内的 Cookie 序列化实现,避免调用方重复声明 cookie 依赖。 */
export const serializeCookie = Cookie.serialize;

export const authCert = async (props: AuthModeType) => {
const result = await parseHeaderCert(props);

Expand All @@ -35,7 +41,7 @@ export async function parseHeaderCert({
// parse jwt
async function authCookieToken(cookie?: string, token?: string) {
// 获取 cookie
const cookies = Cookie.parse(cookie || '');
const cookies = parseCookie(cookie);
const cookieToken = token || cookies[TokenName];

if (!cookieToken) {
Expand Down
Loading
Loading