mirror of
https://github.com/YFGaia/dify-plus.git
synced 2026-06-04 10:14:00 +08:00
fear: admin添加app应用版本管理
system-features添加
This commit is contained in:
+2
-2
@@ -7,11 +7,11 @@ NEXT_PUBLIC_BASE_PATH=
|
||||
# The base URL of console application, refers to the Console base URL of WEB service if console domain is
|
||||
# different from api or web app domain.
|
||||
# example: http://cloud.dify.ai/console/api
|
||||
NEXT_PUBLIC_API_PREFIX=http://localhost:5001/console/api
|
||||
NEXT_PUBLIC_API_PREFIX=http://localhost:3000/console/api
|
||||
# The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from
|
||||
# console or api domain.
|
||||
# example: http://udify.app/api
|
||||
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:5001/api
|
||||
NEXT_PUBLIC_PUBLIC_API_PREFIX=http://localhost:3000/api
|
||||
# When the frontend and backend run on different subdomains, set NEXT_PUBLIC_COOKIE_DOMAIN=1.
|
||||
NEXT_PUBLIC_COOKIE_DOMAIN=
|
||||
|
||||
|
||||
+23
-2
@@ -53,16 +53,37 @@ const getStringConfig = (
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
export const API_PREFIX = getStringConfig(
|
||||
/**
|
||||
* 在浏览器中,若配置的 API 地址为 localhost 或 127.0.0.1,则改为使用当前页面的 origin,
|
||||
* 避免 127.0.0.1 与 localhost 不同源导致 cookie 无法携带(登录后 /api/login/status 拿不到 console 的 access_token)。
|
||||
*/
|
||||
function normalizeSameOriginApiPrefix(raw: string): string {
|
||||
if (typeof globalThis.window === 'undefined' || !raw.startsWith('http'))
|
||||
return raw
|
||||
try {
|
||||
const u = new URL(raw)
|
||||
if (u.hostname === 'localhost' || u.hostname === '127.0.0.1')
|
||||
return globalThis.window.location.origin + (u.pathname.replace(/\/$/, '') || '/')
|
||||
return raw
|
||||
}
|
||||
catch {
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
const _apiPrefixRaw = getStringConfig(
|
||||
process.env.NEXT_PUBLIC_API_PREFIX,
|
||||
DatasetAttr.DATA_API_PREFIX,
|
||||
'http://localhost:5001/console/api',
|
||||
)
|
||||
export const PUBLIC_API_PREFIX = getStringConfig(
|
||||
const _publicApiPrefixRaw = getStringConfig(
|
||||
process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX,
|
||||
DatasetAttr.DATA_PUBLIC_API_PREFIX,
|
||||
'http://localhost:5001/api',
|
||||
)
|
||||
|
||||
export const API_PREFIX = normalizeSameOriginApiPrefix(_apiPrefixRaw)
|
||||
export const PUBLIC_API_PREFIX = normalizeSameOriginApiPrefix(_publicApiPrefixRaw)
|
||||
export const MARKETPLACE_API_PREFIX = getStringConfig(
|
||||
process.env.NEXT_PUBLIC_MARKETPLACE_API_PREFIX,
|
||||
DatasetAttr.DATA_MARKETPLACE_API_PREFIX,
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { SystemFeatures } from '@/types/feature'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { create } from 'zustand'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { consoleClient } from '@/service/client'
|
||||
import { consoleClient, setLoginConfigToken } from '@/service/client'
|
||||
import { defaultSystemFeatures } from '@/types/feature'
|
||||
import { fetchSetupStatusWithCache } from '@/utils/setup-status'
|
||||
|
||||
@@ -21,8 +21,12 @@ export const useGlobalPublicStore = create<GlobalPublicStore>(set => ({
|
||||
const systemFeaturesQueryKey = ['systemFeatures'] as const
|
||||
const setupStatusQueryKey = ['setupStatus'] as const
|
||||
|
||||
// extend: CVE-2025-63387未授权访问 — 先请求 bootstrap 拿 JWT(cookie + body),跨域时用 Header 带 token 请求 login_config
|
||||
async function fetchSystemFeatures() {
|
||||
const data = await consoleClient.systemFeatures()
|
||||
const bootstrapRes = await consoleClient.loginConfigBootstrap()
|
||||
if (bootstrapRes?.token)
|
||||
setLoginConfigToken(bootstrapRes.token)
|
||||
const data = await consoleClient.loginConfig()
|
||||
const { setSystemFeatures } = useGlobalPublicStore.getState()
|
||||
setSystemFeatures({ ...defaultSystemFeatures, ...data })
|
||||
return data
|
||||
|
||||
@@ -2,9 +2,19 @@ import type { SystemFeatures } from '@/types/feature'
|
||||
import { type } from '@orpc/contract'
|
||||
import { base } from '../base'
|
||||
|
||||
export const systemFeaturesContract = base
|
||||
// extend: CVE-2025-63387未授权访问 虽然这个api实际上就是个登录用的
|
||||
export const loginConfigBootstrapContract = base
|
||||
.route({
|
||||
path: '/system-features',
|
||||
path: '/login_config_bootstrap',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<unknown>())
|
||||
.output(type<{ ok: boolean, token: string }>())
|
||||
|
||||
// extend: CVE-2025-63387未授权访问 虽然这个api实际上就是个登录用的 — 路径改为 login_config,需先请求 login_config_bootstrap 写入 cookie
|
||||
export const loginConfigContract = base
|
||||
.route({
|
||||
path: '/login_config',
|
||||
method: 'GET',
|
||||
})
|
||||
.input(type<unknown>())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { InferContractRouterInputs } from '@orpc/contract'
|
||||
import { bindPartnerStackContract, invoicesContract } from './console/billing'
|
||||
import { systemFeaturesContract } from './console/system'
|
||||
// extend: CVE-2025-63387未授权访问 虽然这个api实际上就是个登录用的 — 路径改为 login_config,需先请求 login_config_bootstrap 写入 cookie
|
||||
import { loginConfigBootstrapContract, loginConfigContract } from './console/system'
|
||||
import { trialAppDatasetsContract, trialAppInfoContract, trialAppParametersContract, trialAppWorkflowsContract } from './console/try-app'
|
||||
import { collectionPluginsContract, collectionsContract, searchAdvancedContract } from './marketplace'
|
||||
|
||||
@@ -12,8 +13,10 @@ export const marketplaceRouterContract = {
|
||||
|
||||
export type MarketPlaceInputs = InferContractRouterInputs<typeof marketplaceRouterContract>
|
||||
|
||||
// extend: CVE-2025-63387未授权访问 虽然这个api实际上就是个登录用的 — 路径改为 login_config,需先请求 login_config_bootstrap 写入 cookie
|
||||
export const consoleRouterContract = {
|
||||
systemFeatures: systemFeaturesContract,
|
||||
loginConfigBootstrap: loginConfigBootstrapContract,
|
||||
loginConfig: loginConfigContract,
|
||||
trialApps: {
|
||||
info: trialAppInfoContract,
|
||||
datasets: trialAppDatasetsContract,
|
||||
|
||||
@@ -63,6 +63,15 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
]
|
||||
},
|
||||
// dev 时把 /console/api 和 /api 代理到 5001
|
||||
...(isDev && {
|
||||
async rewrites() {
|
||||
return [
|
||||
{ source: '/console/api/:path*', destination: 'http://localhost:5001/console/api/:path*' },
|
||||
{ source: '/api/:path*', destination: 'http://localhost:5001/api/:path*' },
|
||||
]
|
||||
},
|
||||
}),
|
||||
output: 'standalone',
|
||||
compiler: {
|
||||
removeConsole: isDev ? false : { exclude: ['warn', 'error'] },
|
||||
|
||||
@@ -15,10 +15,23 @@ import {
|
||||
} from '@/contract/router'
|
||||
import { request } from './base'
|
||||
|
||||
// extend: CVE-2025-63387 跨域时 Cookie 可能为 None,用 Header 携带 JWT
|
||||
let loginConfigToken: string | null = null
|
||||
export function setLoginConfigToken(token: string | null) {
|
||||
loginConfigToken = token
|
||||
}
|
||||
|
||||
const getMarketplaceHeaders = () => new Headers({
|
||||
'X-Dify-Version': !IS_MARKETPLACE ? APP_VERSION : '999.0.0',
|
||||
})
|
||||
|
||||
const getConsoleHeaders = () => {
|
||||
const h = new Headers()
|
||||
if (loginConfigToken)
|
||||
h.set('X-Login-Config-Token', loginConfigToken)
|
||||
return h
|
||||
}
|
||||
|
||||
const marketplaceLink = new OpenAPILink(marketplaceRouterContract, {
|
||||
url: MARKETPLACE_API_PREFIX,
|
||||
headers: () => (getMarketplaceHeaders()),
|
||||
@@ -40,6 +53,7 @@ export const marketplaceQuery = createTanstackQueryUtils(marketplaceClient, { pa
|
||||
|
||||
const consoleLink = new OpenAPILink(consoleRouterContract, {
|
||||
url: API_PREFIX,
|
||||
headers: () => getConsoleHeaders(),
|
||||
fetch: (input, init) => {
|
||||
return request(
|
||||
input.url,
|
||||
|
||||
@@ -308,9 +308,9 @@ export const fetchSupportRetrievalMethods = (url: string): Promise<RetrievalMeth
|
||||
return get<RetrievalMethodsRes>(url)
|
||||
}
|
||||
|
||||
// extend: CVE-2025-63387未授权访问 虽然这个api实际上就是个登录用的 — 路径改为 login_config,需先请求 login_config_bootstrap 写入 cookie
|
||||
export const getSystemFeatures = (): Promise<SystemFeatures> => {
|
||||
// extend: 解决登录状况不刷新
|
||||
return get<SystemFeatures>(`/system-features?time=${(Math.round(new Date() / 1000)).toString()}`)
|
||||
return get<SystemFeatures>(`/login_config?time=${(Math.round(new Date() / 1000)).toString()}`)
|
||||
}
|
||||
|
||||
export const enableModel = (url: string, body: { model: string, model_type: ModelTypeEnum }): Promise<CommonResponse> =>
|
||||
|
||||
Reference in New Issue
Block a user