import { Alert, AlertDescription, AlertIcon, AlertTitle, Badge, Button, FormControl, FormHelperText, FormLabel, Heading, HStack, Input, SimpleGrid, VStack, Text, } from "@hope-ui/solid" import { createSignal, For, JSXElement, onCleanup, Show } from "solid-js" import { LinkWithBase, MaybeLoading } from "~/components" import { useFetch, useManageTitle, useRouter, useT } from "~/hooks" import { setMe, me, getSettingBool } from "~/store" import { PEmptyResp, UserMethods, UserPermissions, PResp } from "~/types" import { handleResp, handleRespWithoutNotify, notify, r } from "~/utils" import { WebauthnItem } from "./Webauthnitems" import { RegistrationPublicKeyCredential, create, parseCreationOptionsFromJSON, supported, CredentialCreationOptionsJSON, } from "@github/webauthn-json/browser-ponyfill" import { PublicKeys } from "./PublicKeys" const PermissionBadge = (props: { can: boolean; children: JSXElement }) => { return ( {props.children} ) } const Profile = () => { const t = useT() useManageTitle("manage.sidemenu.profile") const { searchParams, to } = useRouter() const [username, setUsername] = createSignal(me().username) const [password, setPassword] = createSignal("") const [confirmPassword, setConfirmPassword] = createSignal("") const usecompatibility = getSettingBool("sso_compatibility_mode") const [loading, save] = useFetch( (ssoID?: boolean): PEmptyResp => r.post("/me/update", { username: ssoID ? me().username : username(), password: ssoID ? "" : password(), sso_id: me().sso_id, }), ) interface WebauthnItem { fingerprint: string id: string } interface Webauthntemp { session: string options: CredentialCreationOptionsJSON } const [getauthncredentialsloading, getauthncredentials] = useFetch( (): PResp => r.get("/authn/getcredentials"), ) const [, getauthntemp] = useFetch( (): PResp => r.get("/authn/webauthn_begin_registration"), ) const [postregistrationloading, postregistration] = useFetch( ( session: string, credentials: RegistrationPublicKeyCredential, ): PEmptyResp => r.post( "/authn/webauthn_finish_registration", JSON.stringify(credentials), { headers: { session: session, }, }, ), ) const saveMe = async (ssoID?: boolean) => { if (password() && password() !== confirmPassword()) { notify.warning(t("users.confirm_password_not_same")) return } const resp = await save(ssoID) handleResp(resp, () => { setMe({ ...me(), username: username() }) if (!ssoID) { notify.success(t("users.update_profile_success")) to(`/@login?redirect=${encodeURIComponent(location.pathname)}`) } else { to("") } }) } const ssoID = searchParams["sso_id"] if (ssoID) { setMe({ ...me(), sso_id: ssoID }) saveMe(true) } function messageEvent(event: MessageEvent) { const data = event.data if (data.sso_id) { setMe({ ...me(), sso_id: data.sso_id }) saveMe(true) } } window.addEventListener("message", messageEvent) onCleanup(() => { window.removeEventListener("message", messageEvent) }) const [credentials, setcredentials] = createSignal([]) const initauthnEdit = async () => { const resp = await getauthncredentials() handleRespWithoutNotify(resp, setcredentials) } if ( supported() && !UserMethods.is_guest(me()) && getSettingBool("webauthn_login_enabled") ) { initauthnEdit() } return ( {t("users.guest-tips")} {t("users.modify_nothing")} {t("global.have_account")} {t("global.go_login")} } > {t("users.update_profile")} {t("users.change_username")} { setUsername(e.currentTarget.value) }} /> {t("users.change_password")} { setPassword(e.currentTarget.value) }} /> {t("users.change_password-tips")} {t("users.confirm_password")} { setConfirmPassword(e.currentTarget.value) }} /> {t("users.confirm_password-tips")} {t("users.sso_login")} { const url = r.getUri() + "/auth/sso?method=get_sso_id" if (usecompatibility) { window.location.href = url return } window.open(url, "authPopup", "width=500,height=600") }} > {t("users.connect_sso")} } > {t("users.webauthn")} {(item) => ( )} {(item, i) => ( {t(`users.permissions.${item}`)} )} ) } export default Profile