import LogoIcon from '@/assets/images/gpustack-logo.png'; import { initialPasswordAtom, userAtom } from '@/atoms/user'; import LangSelect from '@/components/lang-select'; import SealInput from '@/components/seal-form/seal-input'; import ThemeDropActions from '@/components/theme-toggle/theme-drop-actions'; import externalLinks from '@/constants/external-links'; import { CRYPT_TEXT, REMEMBER_ME_KEY, getRememberMe, rememberMe, removeRememberMe } from '@/utils/localstore/index'; import { LockOutlined, UserOutlined } from '@ant-design/icons'; import { useIntl, useModel } from '@umijs/max'; import { Button, Checkbox, Form } from 'antd'; import { createStyles } from 'antd-style'; import CryptoJS from 'crypto-js'; import { useAtom } from 'jotai'; import { useEffect, useMemo } from 'react'; import { flushSync } from 'react-dom'; import { login } from '../apis'; import { checkDefaultPage } from '../utils'; const authConfig = await fetchAuthConfig('/get_config'); // get authentication configuration const useStyles = createStyles(({ token, css }) => ({ header: css` display: flex; align-items: center; gap: 8px; position: fixed; right: 0; top: 0; height: 60px; padding: 20px; .anticon-global { color: ${token.colorText}; } .anticon:hover { color: ${token.colorTextTertiary}; } ` })); // function authentication configuration method async function fetchAuthConfig(url) { try { const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); } catch (error) { console.error('OIDC config error:', error); throw error; } }; const LoginForm = () => { const { styles } = useStyles(); const [userInfo, setUserInfo] = useAtom(userAtom); const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom); const { initialState, setInitialState } = useModel('@@initialState') || {}; const intl = useIntl(); const [form] = Form.useForm(); const renderWelCome = useMemo(() => { return (
{intl?.formatMessage({ id: 'users.login.title' })} logo
); }, [intl]); const gotoDefaultPage = async (userInfo: any) => { checkDefaultPage(userInfo, true); }; const fetchUserInfo = async () => { const userInfo = await initialState?.fetchUserInfo?.(); if (userInfo) { flushSync(() => { setInitialState((s: any) => ({ ...s, currentUser: userInfo })); }); } return userInfo; }; const encryptPassword = (password: string) => { const psw = CryptoJS.AES?.encrypt?.(password, CRYPT_TEXT).toString(); return psw; }; const decryptPassword = (password: string) => { const bytes = CryptoJS.AES?.decrypt?.(password, CRYPT_TEXT); const res = bytes.toString(CryptoJS.enc.Utf8); return res; }; const callRememberMe = async (values: any) => { const { autoLogin } = values; if (autoLogin) { await rememberMe(REMEMBER_ME_KEY, { um: encryptPassword(values.username), pw: encryptPassword(values.password), f: true }); } else { await removeRememberMe(REMEMBER_ME_KEY); } }; const callGetRememberMe = async () => { const rememberMe = await getRememberMe(REMEMBER_ME_KEY); if (rememberMe?.f) { const username = decryptPassword(rememberMe?.um); const password = decryptPassword(rememberMe?.pw); form.setFieldsValue({ username, password, autoLogin: true }); } }; // OIDC certification const handleOidcLogin = async () => { const authUrl = `${authConfig.base_entrypoint}auth?response_type=code&client_id=${authConfig.CLIENT_ID}&redirect_uri=${authConfig.redirect_uri}&scope=openid profile email&state=random_state_string`; window.location.href = authUrl;}; // SAML certification const handleSamlLogin = async () => { window.location.href = "/auth/saml/login";} // Handling certification callbacks useEffect(() => { const params = new URLSearchParams(window.location.search); const code = params.get('code'); // OIDC callback information console.log(code) const samlResponse = params.get('SAMLResponse'); // SAML callback information const allParams = Object.fromEntries(params.entries()); history.replaceState({}, '', window.location.pathname); if (code) { login({ code: code }).then(async () => { const userInfo = await fetchUserInfo(); await setUserInfo(userInfo); gotoDefaultPage(userInfo); }); }; if (samlResponse) { login({ SAMLResponse: decodeURIComponent(samlResponse) }).then(async () => { const userInfo = await fetchUserInfo(); await setUserInfo(userInfo); gotoDefaultPage(userInfo); })}; }, []); const handleLogin = async (values: any) => { try { await login({ username: values.username, password: values.password }); const userInfo = await fetchUserInfo(); setUserInfo(userInfo); if (values.autoLogin) { await callRememberMe(values); } else { await removeRememberMe(REMEMBER_ME_KEY); } if (!userInfo?.require_password_change) { gotoDefaultPage(userInfo); } else { setInitialPassword(encryptPassword(values.password)); } } catch (error) { // to do something } }; useEffect(() => { callGetRememberMe(); }, []); return (
{renderWelCome} } /> } label={intl.formatMessage({ id: 'common.form.password' })} />
{intl.formatMessage({ id: 'common.login.rember' })}
); }; export default LoginForm;