Files
FastGPT/packages/service/support/permission/app/auth.ts
T
Archer 2e18f1ebc2 next 15 (#6457)
* next 15

* lock

* feat: rename .d.ts to .ts for Next 15 compatibility

- Rename 104 .d.ts files to .ts (Next 15 no longer supports .d.ts in src)
- Remove 5 redundant .d.ts files that had .ts counterparts
- Update all import paths: remove .d suffix from 100 import statements
- Update tsconfig.json include patterns across all packages
- Add pnpm overrides to unify react@18.3.1 across monorepo
- Fix react version mismatch (packages/global and packages/service were resolving to react@19.1.1)

* fix: resolve 61 TypeScript errors from .d.ts to .ts migration

- Fix broken imports using non-relative module paths (e.g. 'support/user/team/type' → relative paths)
- Remove unused/dead imports referencing deleted modules
- Fix duplicate identifiers (show_emptyChat, concatMd, TrainingModeEnum)
- Add missing imports (BoxProps, GroupMemberRole, UsageSourceEnum, dashboard_evaluation)
- Fix generic type constraints (OutLinkEditType, createShareChat)
- Replace removed types with correct alternatives (ChatModelItemType → LLMModelItemType)
- Delete 5 dead code files with 0 references
- Add global type declaration for countTrackQueue
- Fix nullable type narrowing (sourceMember, ParentIdType, optional app fields)

* refactor: replace as ClientSession assertion with proper type narrowing via Omit & intersection

* fix: remove experimental.workerThreads to fix DataCloneError in Next 15 static generation

Next 15 worker threads attempt to structuredClone the config object,
which fails on the webpack function. workerThreads is not needed for
the build to work correctly.

* Update document/content/docs/upgrading/4-14/4148.mdx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* fix: ts

* update next config

* update next

* fix: dockerfile

* fix: comment

---------

Co-authored-by: Archer <c121914yu@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-25 18:28:16 +08:00

165 lines
4.0 KiB
TypeScript

/* Auth app permission */
import { MongoApp } from '../../../core/app/schema';
import { type AppDetailType } from '@fastgpt/global/core/app/type';
import {
NullRoleVal,
PerResourceTypeEnum,
ReadPermissionVal,
ReadRoleVal
} from '@fastgpt/global/support/permission/constant';
import { AppErrEnum } from '@fastgpt/global/common/error/code/app';
import { getTmbInfoByTmbId } from '../../user/team/controller';
import { getTmbPermission } from '../controller';
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';
import { type PermissionValueType } from '@fastgpt/global/support/permission/type';
import { AppFolderTypeList, AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { type ParentIdType } from '@fastgpt/global/common/parentFolder/type';
import { type AuthModeType, type AuthResponseType } from '../type';
import { splitCombineToolId } from '@fastgpt/global/core/app/tool/utils';
import { AppReadChatLogPerVal } from '@fastgpt/global/support/permission/app/constant';
import { parseHeaderCert } from '../auth/common';
import { sumPer } from '@fastgpt/global/support/permission/utils';
export const authPluginByTmbId = async ({
tmbId,
appId,
per
}: {
tmbId: string;
appId: string;
per: PermissionValueType;
}) => {
const { authAppId } = splitCombineToolId(appId);
if (authAppId) {
const { app } = await authAppByTmbId({
appId: authAppId,
tmbId,
per
});
return app;
}
};
export const authAppByTmbId = async ({
tmbId,
appId,
per,
isRoot
}: {
tmbId: string;
appId: string;
per: PermissionValueType;
isRoot?: boolean;
}): Promise<{
app: AppDetailType;
}> => {
const { teamId, permission: tmbPer } = await getTmbInfoByTmbId({ tmbId });
const app = await (async () => {
const app = await MongoApp.findOne({ _id: appId }).lean();
if (!app) {
return Promise.reject(AppErrEnum.unExist);
}
if (isRoot) {
return {
...app,
permission: new AppPermission({ isOwner: true })
};
}
if (String(app.teamId) !== teamId) {
return Promise.reject(AppErrEnum.unAuthApp);
}
if (app.type === AppTypeEnum.hidden) {
if (per === AppReadChatLogPerVal) {
if (!tmbPer.hasManagePer) {
return Promise.reject(AppErrEnum.unAuthApp);
}
} else if (per !== ReadPermissionVal) {
return Promise.reject(AppErrEnum.unAuthApp);
}
return {
...app,
permission: new AppPermission({ isOwner: false, role: ReadRoleVal })
};
}
const isOwner = tmbPer.isOwner || String(app.tmbId) === String(tmbId);
const isGetParentClb =
app.inheritPermission && !AppFolderTypeList.includes(app.type) && !!app.parentId;
const [folderPer = NullRoleVal, myPer = NullRoleVal] = await Promise.all([
isGetParentClb
? getTmbPermission({
teamId,
tmbId,
resourceId: app.parentId!,
resourceType: PerResourceTypeEnum.app
})
: NullRoleVal,
getTmbPermission({
teamId,
tmbId,
resourceId: appId,
resourceType: PerResourceTypeEnum.app
})
]);
const Per = new AppPermission({ role: sumPer(folderPer, myPer), isOwner });
if (app.favourite || app.quick) {
Per.addRole(ReadRoleVal);
}
if (!Per.checkPer(per)) {
return Promise.reject(AppErrEnum.unAuthApp);
}
return {
...app,
permission: Per
};
})();
return { app };
};
export const authApp = async ({
appId,
per,
...props
}: AuthModeType & {
appId: ParentIdType;
per: PermissionValueType;
}): Promise<
AuthResponseType<AppPermission> & {
app: AppDetailType;
}
> => {
const result = await parseHeaderCert(props);
const { tmbId } = result;
if (!appId) {
return Promise.reject(AppErrEnum.unExist);
}
const { app } = await authAppByTmbId({
tmbId,
appId,
per,
isRoot: result.isRoot
});
return {
...result,
permission: app.permission,
app
};
};