diff --git a/ui/package.json b/ui/package.json index d0c3394c5..10b8eb1b8 100644 --- a/ui/package.json +++ b/ui/package.json @@ -27,7 +27,6 @@ "@wecom/jssdk": "^2.3.1", "axios": "^1.8.4", "cropperjs": "^1.6.2", - "crypto-js": "^4.2.0", "dingtalk-jsapi": "^3.1.0", "echarts": "^5.6.0", "element-plus": "^2.10.2", @@ -42,6 +41,7 @@ "mermaid": "^10.9.0", "moment": "^2.30.1", "nanoid": "^5.1.5", + "node-forge": "^1.3.1", "nprogress": "^0.2.0", "pinia": "^3.0.1", "recorder-core": "^1.3.25011100", @@ -64,6 +64,7 @@ "@types/crypto-js": "^4.2.2", "@types/file-saver": "^2.0.7", "@types/node": "^22.14.0", + "@types/node-forge": "^1.3.14", "@types/nprogress": "^0.2.3", "@vitejs/plugin-vue": "^5.2.3", "@vitejs/plugin-vue-jsx": "^4.1.2", diff --git a/ui/src/api/type/chat.ts b/ui/src/api/type/chat.ts index e5691b537..1bd0a210a 100644 --- a/ui/src/api/type/chat.ts +++ b/ui/src/api/type/chat.ts @@ -12,6 +12,7 @@ interface ChatProfile { // 登录类型 login_value?: Array max_attempts?: number + rasKey?: string } interface ChatUserProfile { diff --git a/ui/src/api/type/login.ts b/ui/src/api/type/login.ts index d2c41a8b2..bddc1ef8d 100644 --- a/ui/src/api/type/login.ts +++ b/ui/src/api/type/login.ts @@ -11,5 +11,9 @@ interface LoginRequest { * 验证码 */ captcha: string + /** + * 加密数据 + */ + encryptedData?: string } export type { LoginRequest } diff --git a/ui/src/stores/modules/chat-user.ts b/ui/src/stores/modules/chat-user.ts index a6168ecac..2d05affb9 100644 --- a/ui/src/stores/modules/chat-user.ts +++ b/ui/src/stores/modules/chat-user.ts @@ -94,7 +94,7 @@ const useChatUserStore = defineStore('chat-user', { return this.token }) }, - login(request: LoginRequest, loading?: Ref) { + login(request: any, loading?: Ref) { return ChatAPI.login(this.accessToken as string, request, loading).then((ok) => { this.setToken(ok.data.token) return this.token diff --git a/ui/src/stores/modules/login.ts b/ui/src/stores/modules/login.ts index 592566e01..1f9fcd8e5 100644 --- a/ui/src/stores/modules/login.ts +++ b/ui/src/stores/modules/login.ts @@ -16,7 +16,7 @@ const useLoginStore = defineStore('login', { return localStorage.getItem('token') }, - async asyncLogin(data: LoginRequest, loading?: Ref) { + async asyncLogin(data: any, loading?: Ref) { return LoginApi.login(data).then((ok) => { this.token = ok?.data?.token localStorage.setItem('token', ok?.data?.token) diff --git a/ui/src/stores/modules/user.ts b/ui/src/stores/modules/user.ts index 57f6b0f72..68aa5ae6e 100644 --- a/ui/src/stores/modules/user.ts +++ b/ui/src/stores/modules/user.ts @@ -16,7 +16,8 @@ export interface userStateTypes { license_is_valid: boolean edition: 'CE' | 'PE' | 'EE' workspace_id: string - workspace_list: Array + workspace_list: Array, + rasKey: string } const useUserStore = defineStore('user', { @@ -27,6 +28,7 @@ const useUserStore = defineStore('user', { edition: 'CE', workspace_id: '', workspace_list: [], + rasKey: '', }), actions: { getLanguage() { @@ -140,6 +142,7 @@ const useUserStore = defineStore('user', { this.license_is_valid = ok.data.license_is_valid this.edition = ok.data.edition this.version = ok.data.version + this.rasKey = ok.data.ras const theme = useThemeStore() if (this.isEE() || this.isPE()) { await theme.theme() diff --git a/ui/src/views/chat/user-login/index.vue b/ui/src/views/chat/user-login/index.vue index 5667aad73..af11308f3 100644 --- a/ui/src/views/chat/user-login/index.vue +++ b/ui/src/views/chat/user-login/index.vue @@ -180,7 +180,7 @@ import QrCodeTab from '@/views/chat/user-login/scanCompinents/QrCodeTab.vue' import {MsgConfirm, MsgError} from '@/utils/message.ts' import PasswordAuth from '@/views/chat/auth/component/password.vue' import {isAppIcon} from '@/utils/common' -import CryptoJS from "crypto-js"; +import forge from "node-forge"; useResize() const router = useRouter() @@ -250,8 +250,13 @@ const loginHandle = () => { }) }) } else { - loginForm.value.password = CryptoJS.MD5(loginForm.value.password.trim()).toString(CryptoJS.enc.Hex) - chatUser.login(loginForm.value).then((ok) => { + const publicKey = forge.pki.publicKeyFromPem(chatUser?.chat_profile?.rasKey as any); + const encrypted = publicKey.encrypt(JSON.stringify(loginForm.value), 'RSAES-PKCS1-V1_5'); + const encryptedBase64 = forge.util.encode64(encrypted); + chatUser.login({ + encryptedData: encryptedBase64, + username: loginForm.value.username + }).then((ok) => { router.push({ name: 'chat', params: {accessToken: chatUser.accessToken}, diff --git a/ui/src/views/login/index.vue b/ui/src/views/login/index.vue index eca9879dd..9888e195c 100644 --- a/ui/src/views/login/index.vue +++ b/ui/src/views/login/index.vue @@ -141,7 +141,7 @@ import QrCodeTab from '@/views/login/scanCompinents/QrCodeTab.vue' import {MsgConfirm, MsgError} from '@/utils/message.ts' import * as dd from 'dingtalk-jsapi' import {loadScript} from '@/utils/common' -import CryptoJS from 'crypto-js'; +import forge from 'node-forge'; const router = useRouter() const {login, user, theme} = useStore() @@ -200,9 +200,11 @@ const loginHandle = () => { loading.value = false }) } else { - loginForm.value.password = CryptoJS.MD5(loginForm.value.password.trim()).toString(CryptoJS.enc.Hex) + const publicKey = forge.pki.publicKeyFromPem(user.rasKey); + const encrypted = publicKey.encrypt(JSON.stringify(loginForm.value), 'RSAES-PKCS1-V1_5'); + const encryptedBase64 = forge.util.encode64(encrypted); login - .asyncLogin(loginForm.value) + .asyncLogin({encryptedData: encryptedBase64, username: loginForm.value.username}) .then(() => { locale.value = localStorage.getItem('MaxKB-locale') || getBrowserLang() || 'en-US' localStorage.setItem('workspace_id', 'default') @@ -298,7 +300,7 @@ onBeforeMount(() => { } else { authSetting.value = { max_attempts: 1, - default_value: 'password', + default_value: 'LOCAL', } } const params = route.query @@ -315,7 +317,7 @@ onBeforeMount(() => { } else { authSetting.value = { max_attempts: 1, - default_value: 'password', + default_value: 'LOCAL', } } }) @@ -351,7 +353,7 @@ const newDefaultSlogan = computed(() => { }) function redirectAuth(authType: string, needMessage: boolean = true) { - if (authType === 'LDAP' || authType === '' || authType === 'password') { + if (authType === 'LDAP' || authType === '' || authType === 'LOCAL') { return } authApi.getLoginViewAuthSetting(authType, loading).then((res: any) => { diff --git a/ui/src/views/system-setting/authentication/component/Setting.vue b/ui/src/views/system-setting/authentication/component/Setting.vue index b51244c63..d9b009017 100644 --- a/ui/src/views/system-setting/authentication/component/Setting.vue +++ b/ui/src/views/system-setting/authentication/component/Setting.vue @@ -84,7 +84,7 @@ const authFormRef = ref(); const form = ref({ - default_value: 'password', + default_value: 'LOCAL', max_attempts: 1, }) diff --git a/ui/src/workflow/nodes/image-to-video/index.vue b/ui/src/workflow/nodes/image-to-video/index.vue index 69986102f..f23598a37 100644 --- a/ui/src/workflow/nodes/image-to-video/index.vue +++ b/ui/src/workflow/nodes/image-to-video/index.vue @@ -171,6 +171,7 @@ :placeholder=" $t('views.applicationWorkflow.nodes.imageToVideoGenerate.last_frame.requiredMessage') " + clearable v-model="form_data.last_frame_url" />