From 5ff8a7f600f796905a0adb278542fd7921d7c372 Mon Sep 17 00:00:00 2001 From: Garfield Dai Date: Wed, 13 Nov 2024 18:23:08 +0800 Subject: [PATCH 1/2] update --- web/i18n/en-US/login.ts | 2 +- web/i18n/zh-Hans/login.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/i18n/en-US/login.ts b/web/i18n/en-US/login.ts index da7318bb99..5ff7b80b4e 100644 --- a/web/i18n/en-US/login.ts +++ b/web/i18n/en-US/login.ts @@ -101,7 +101,7 @@ const translation = { licenseExpired: 'License Expired', licenseExpiredTip: 'The Dify Enterprise license for your workspace has expired. Please contact your administrator to continue using Dify.', licenseLost: 'License Lost', - licenseLostTip: 'The Dify Enterprise license server for your workspace lost. Please contact your administrator to continue using Dify.', + licenseLostTip: 'Failed to connect Dify license server. Please contact your administrator to continue using Dify.', licenseInactive: 'License Inactive', licenseInactiveTip: 'The Dify Enterprise license for your workspace is inactive. Please contact your administrator to continue using Dify.', } diff --git a/web/i18n/zh-Hans/login.ts b/web/i18n/zh-Hans/login.ts index 4f73723c97..7f64c954b1 100644 --- a/web/i18n/zh-Hans/login.ts +++ b/web/i18n/zh-Hans/login.ts @@ -101,8 +101,8 @@ const translation = { noLoginMethodTip: '请联系系统管理员添加身份认证方式', licenseExpired: '许可证已过期', licenseExpiredTip: '您所在空间的 Dify Enterprise 许可证已过期,请联系管理员以继续使用 Dify。', - licenseLost: '认证服务器丢失', - licenseLostTip: '您所在空间的 Dify Enterprise 认证服务器已丢失,请联系管理员以继续使用 Dify。', + licenseLost: '许可证丢失', + licenseLostTip: '无法连接 Dify 许可证服务器,请联系管理员以继续使用 Dify。', licenseInactive: '许可证未激活', licenseInactiveTip: '您所在空间的 Dify Enterprise 许可证尚未激活,请联系管理员以继续使用 Dify。', } From a66e44211b03b45ff028b1d7e8a2a03ff6e86a6d Mon Sep 17 00:00:00 2001 From: NFish Date: Thu, 14 Nov 2024 10:34:39 +0800 Subject: [PATCH 2/2] fix: supports force logout when license expired or license server lost --- web/service/base.ts | 163 +++++++++++++++++++++++++++++++------------- web/utils/index.ts | 6 +- 2 files changed, 119 insertions(+), 50 deletions(-) diff --git a/web/service/base.ts b/web/service/base.ts index 6cb732c55d..6bb5979d70 100644 --- a/web/service/base.ts +++ b/web/service/base.ts @@ -17,6 +17,7 @@ import type { WorkflowStartedResponse, } from '@/types/workflow' import { removeAccessToken } from '@/app/components/share/utils' +import { asyncRunSafe } from '@/utils' const TIME_OUT = 100000 const ContentType = { @@ -550,55 +551,125 @@ export const ssePost = ( } // base request -export const request = (url: string, options = {}, otherOptions?: IOtherOptions) => { - return new Promise((resolve, reject) => { +export const request = async(url: string, options = {}, otherOptions?: IOtherOptions) => { + try { const otherOptionsForBaseFetch = otherOptions || {} - baseFetch(url, options, otherOptionsForBaseFetch).then(resolve).catch((errResp) => { - if (errResp?.status === 401) { - return refreshAccessTokenOrRelogin(TIME_OUT).then(() => { - baseFetch(url, options, otherOptionsForBaseFetch).then(resolve).catch(reject) - }).catch(() => { - const { - isPublicAPI = false, - silent, - } = otherOptionsForBaseFetch - const bodyJson = errResp.json() - if (isPublicAPI) { - return bodyJson.then((data: ResponseError) => { - if (data.code === 'web_sso_auth_required') - requiredWebSSOLogin() - - if (data.code === 'unauthorized') { - removeAccessToken() - globalThis.location.reload() - } - - return Promise.reject(data) - }) - } - const loginUrl = `${globalThis.location.origin}/signin` - bodyJson.then((data: ResponseError) => { - if (data.code === 'init_validate_failed' && IS_CE_EDITION && !silent) - Toast.notify({ type: 'error', message: data.message, duration: 4000 }) - else if (data.code === 'not_init_validated' && IS_CE_EDITION) - globalThis.location.href = `${globalThis.location.origin}/init` - else if (data.code === 'not_setup' && IS_CE_EDITION) - globalThis.location.href = `${globalThis.location.origin}/install` - else if (location.pathname !== '/signin' || !IS_CE_EDITION) - globalThis.location.href = loginUrl - else if (!silent) - Toast.notify({ type: 'error', message: data.message }) - }).catch(() => { - // Handle any other errors - globalThis.location.href = loginUrl - }) - }) + const [err, resp] = await asyncRunSafe(baseFetch(url, options, otherOptionsForBaseFetch)) + if (err === null) + return resp + const errResp: Response = err as any + if (errResp.status === 401) { + const [parseErr, errRespData] = await asyncRunSafe(errResp.json()) + const loginUrl = `${globalThis.location.origin}/signin` + if (parseErr) { + globalThis.location.href = loginUrl + return Promise.reject(err) } - else { - reject(errResp) + // special code + const { code, message } = errRespData + // webapp sso + if (code === 'web_sso_auth_required') { + requiredWebSSOLogin() + return Promise.reject(err) } - }) - }) + // force logout + if (code === 'unauthorized_and_force_logout') { + removeAccessToken() + globalThis.location.reload() + return Promise.reject(err) + } + const { + isPublicAPI = false, + silent, + } = otherOptionsForBaseFetch + if (isPublicAPI && code === 'unauthorized') { + removeAccessToken() + globalThis.location.reload() + return Promise.reject(err) + } + if (code === 'init_validate_failed' && IS_CE_EDITION && !silent) { + Toast.notify({ type: 'error', message, duration: 4000 }) + return Promise.reject(err) + } + if (code === 'not_init_validated' && IS_CE_EDITION) { + globalThis.location.href = `${globalThis.location.origin}/init` + return Promise.reject(err) + } + if (code === 'not_setup' && IS_CE_EDITION) { + globalThis.location.href = `${globalThis.location.origin}/install` + return Promise.reject(err) + } + + // refresh token + const [refreshErr] = await asyncRunSafe(refreshAccessTokenOrRelogin(TIME_OUT)) + if (refreshErr === null) + return baseFetch(url, options, otherOptionsForBaseFetch) + if (location.pathname !== '/signin' || !IS_CE_EDITION) { + globalThis.location.href = loginUrl + return Promise.reject(err) + } + if (!silent) { + Toast.notify({ type: 'error', message }) + return Promise.reject(err) + } + globalThis.location.href = loginUrl + return Promise.reject(err) + } + else { + return Promise.reject(err) + } + } + catch (error) { + console.error(error) + return Promise.reject(error) + } + // return new Promise((resolve, reject) => { + // baseFetch(url, options, otherOptionsForBaseFetch).then(resolve).catch((errResp) => { + // if (errResp?.status === 401) { + // return refreshAccessTokenOrRelogin(TIME_OUT).then(() => { + // baseFetch(url, options, otherOptionsForBaseFetch).then(resolve).catch(reject) + // }).catch(() => { + // const { + // isPublicAPI = false, + // silent, + // } = otherOptionsForBaseFetch + // const bodyJson = errResp.json() + // if (isPublicAPI) { + // return bodyJson.then((data: ResponseError) => { + // if (data.code === 'web_sso_auth_required') + // requiredWebSSOLogin() + + // if (data.code === 'unauthorized') { + // removeAccessToken() + // globalThis.location.reload() + // } + + // return Promise.reject(data) + // }) + // } + // const loginUrl = `${globalThis.location.origin}/signin` + // bodyJson.then((data: ResponseError) => { + // if (data.code === 'init_validate_failed' && IS_CE_EDITION && !silent) + // Toast.notify({ type: 'error', message: data.message, duration: 4000 }) + // else if (data.code === 'not_init_validated' && IS_CE_EDITION) + // globalThis.location.href = `${globalThis.location.origin}/init` + // else if (data.code === 'not_setup' && IS_CE_EDITION) + // globalThis.location.href = `${globalThis.location.origin}/install` + // else if (location.pathname !== '/signin' || !IS_CE_EDITION) + // globalThis.location.href = loginUrl + // else if (!silent) + // Toast.notify({ type: 'error', message: data.message }) + // }).catch(() => { + // // Handle any other errors + // globalThis.location.href = loginUrl + // }) + // }) + // } + // else { + // reject(errResp) + // } + // }) + // }) } // request methods diff --git a/web/utils/index.ts b/web/utils/index.ts index 7aa6fef0a8..cabad6c35c 100644 --- a/web/utils/index.ts +++ b/web/utils/index.ts @@ -8,10 +8,8 @@ export async function asyncRunSafe(fn: Promise): Promise<[Error] | [ try { return [null, await fn] } - catch (e) { - if (e instanceof Error) - return [e] - return [new Error('unknown error')] + catch (e: any) { + return [e || new Error('unknown error')] } }