From 75ae98c855fdd10fc23cdb7389f2cfc6afee4393 Mon Sep 17 00:00:00 2001 From: breadddevv Date: Fri, 19 Jun 2026 17:46:04 +0100 Subject: [PATCH] Fixed 401 error --- pages/login.tsx | 892 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 604 insertions(+), 288 deletions(-) diff --git a/pages/login.tsx b/pages/login.tsx index 50464743..d42a646c 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -56,7 +56,14 @@ function AuthSubmitButton({ viewBox="0 0 24 24" aria-hidden > - + >> 0; + for (let i = 0; i < displayName.length; i++) + n = (n * 31 + displayName.charCodeAt(i)) >>> 0; return AVATAR_BG_COLORS[n % AVATAR_BG_COLORS.length]; } @@ -119,13 +147,19 @@ const Login: NextPage = () => { const [signupStep, setSignupStep] = useState<0 | 1 | 2 | 3>(0); const [signupThumbnail, setSignupThumbnail] = useState(""); const [signupDisplayName, setSignupDisplayName] = useState(""); - const [signupUserid, setSignupUserid] = useState(undefined); + const [signupUserid, setSignupUserid] = useState( + undefined, + ); const [verificationCode, setVerificationCode] = useState(""); - const [verificationError, setVerificationError] = useState(null); + const [verificationError, setVerificationError] = useState( + null, + ); const [showPassword, setShowPassword] = useState(false); const [showCopyright, setShowCopyright] = useState(false); const [usernameCheckLoading, setUsernameCheckLoading] = useState(false); - const [usernameAvailable, setUsernameAvailable] = useState(null); + const [usernameAvailable, setUsernameAvailable] = useState( + null, + ); const [showTraditionalLogin, setShowTraditionalLogin] = useState(false); const errorToastShown = useRef(false); @@ -145,32 +179,55 @@ const Login: NextPage = () => { setUsernameCheckLoading(false); setUsernameAvailable(null); setShowTraditionalLogin(false); - if (usernameCheckTimeout.current) clearTimeout(usernameCheckTimeout.current); + if (usernameCheckTimeout.current) + clearTimeout(usernameCheckTimeout.current); }, [mode]); useEffect(() => { + let isMounted = true; + async function fetchMe() { - const userInfo = await axios.get('/api/@me'); - if (userInfo.status === 200) Router.push('/'); + try { + const userInfo = await axios.get("/api/@me"); + if (isMounted && userInfo.status === 200) { + Router.push("/"); + } + } catch (error) { + console.log("User not authenticated"); + } } async function fetchBackground() { try { - const res = await axios.get('/api/instance/login-background'); - if (res.data.backgroundUrl) setLoginBg(res.data.backgroundUrl); + const res = await axios.get("/api/instance/login-background"); + if (!isMounted) return; + + if (res.data.backgroundUrl) { + setLoginBg(res.data.backgroundUrl); + } if (res.data.themeRgb) { - document.documentElement.style.setProperty('--group-theme', res.data.themeRgb); + document.documentElement.style.setProperty( + "--group-theme", + res.data.themeRgb, + ); } - } catch {} + } catch (error) { + console.error("Failed to fetch background:", error); + } } fetchMe(); fetchBackground(); + + return () => { + isMounted = false; + }; }, []); useEffect(() => { return () => { - if (usernameCheckTimeout.current) clearTimeout(usernameCheckTimeout.current); + if (usernameCheckTimeout.current) + clearTimeout(usernameCheckTimeout.current); }; }, []); @@ -197,7 +254,8 @@ const Login: NextPage = () => { }; const onUsernameChange = (username: string) => { - if (usernameCheckTimeout.current) clearTimeout(usernameCheckTimeout.current); + if (usernameCheckTimeout.current) + clearTimeout(usernameCheckTimeout.current); signupMethods.clearErrors("username"); setUsernameAvailable(null); usernameCheckTimeout.current = setTimeout(() => { @@ -205,7 +263,9 @@ const Login: NextPage = () => { }, 800); }; - const signupUsernameReg = regSignup("username", { required: "This field is required" }); + const signupUsernameReg = regSignup("username", { + required: "This field is required", + }); const signupUsernameProps = { ...signupUsernameReg, onChange: (e: Parameters[0]) => { @@ -221,28 +281,47 @@ const Login: NextPage = () => { const req = await axios.post("/api/auth/login", data).catch((e: any) => { setLoading(false); if (e.response?.status === 404) { - setErrLogin("username", { type: "custom", message: e.response.data.error }); + setErrLogin("username", { + type: "custom", + message: e.response.data.error, + }); } else if (e.response?.status === 401) { - setErrLogin("password", { type: "custom", message: e.response.data.error }); + setErrLogin("password", { + type: "custom", + message: e.response.data.error, + }); } else { - setErrLogin("username", { type: "custom", message: "Something went wrong" }); - setErrLogin("password", { type: "custom", message: "Something went wrong" }); + setErrLogin("username", { + type: "custom", + message: "Something went wrong", + }); + setErrLogin("password", { + type: "custom", + message: "Something went wrong", + }); } throw e; }); const { data: res } = req; setLogin({ ...res.user, workspaces: res.workspaces }); Router.push("/"); - } catch {} - finally { + } catch { + } finally { setLoading(false); } }; // Step 2 → 3: call start, store both code and token - const onSubmitSignup: SubmitHandler = async ({ username, password, verifypassword }) => { + const onSubmitSignup: SubmitHandler = async ({ + username, + password, + verifypassword, + }) => { if (password !== verifypassword) { - setErrSignup("verifypassword", { type: "validate", message: "Passwords must match" }); + setErrSignup("verifypassword", { + type: "validate", + message: "Passwords must match", + }); return; } setLoading(true); @@ -276,7 +355,9 @@ const Login: NextPage = () => { if (data.success) Router.push("/"); else setVerificationError("Verification failed. Please try again."); } catch (e: any) { - setVerificationError(e?.response?.data?.error || "Verification not found. Please try again."); + setVerificationError( + e?.response?.data?.error || "Verification not found. Please try again.", + ); } finally { setLoading(false); } @@ -286,37 +367,70 @@ const Login: NextPage = () => { if (!Router.isReady || errorToastShown.current) return; const { error, action, ...rest } = Router.query; if (error) { - if (error === "discord-not-linked") toast.error("This account isn't linked to any Orbit account."); - else if (error === "google-not-linked") toast.error("Your Google account is not linked."); - else if (error === "state-mismatch") toast.error("We detected a state mismatch, OAuth process was discontinued."); - else if (error === "missing_params") toast.error("Not enough params were provided."); - else if (error === "unauthorized-domain") toast.error("This domain is not allowed to sign in."); + if (error === "discord-not-linked") + toast.error("This account isn't linked to any Orbit account."); + else if (error === "google-not-linked") + toast.error("Your Google account is not linked."); + else if (error === "state-mismatch") + toast.error( + "We detected a state mismatch, OAuth process was discontinued.", + ); + else if (error === "missing_params") + toast.error("Not enough params were provided."); + else if (error === "unauthorized-domain") + toast.error("This domain is not allowed to sign in."); else toast.error("There was an error while logging in."); errorToastShown.current = true; - Router.replace({ pathname: Router.pathname, query: rest }, undefined, { shallow: true }); + Router.replace({ pathname: Router.pathname, query: rest }, undefined, { + shallow: true, + }); } }, [Router.isReady, Router.query]); const OAuthButtons = ({ className }: { className?: string }) => (
{isRobloxOAuth && ( - )} {isDiscordOAuth && ( - )} {isGoogleOAuth && ( - )} @@ -329,7 +443,9 @@ const Login: NextPage = () => {
- or + + or +
); @@ -343,8 +459,15 @@ const Login: NextPage = () => {
{loginBg ? ( <> -
-
+
+
) : null}
{ Account

- Welcome to{" "} - Orbit + Welcome to Orbit

Sign in or create an account to access your workspaces. @@ -374,282 +496,476 @@ const Login: NextPage = () => {

-
- - {mode === "login" && ( - <> -

Sign in

-

- {effectiveOAuthOnly && !showTraditionalLogin - ? "Use one of the options below to sign in." - : "Use your username and password to continue." - } -

- - {effectiveOAuthOnly && !showTraditionalLogin && ( -
- -
- +
+ {mode === "login" && ( + <> +

+ Sign in +

+

+ {effectiveOAuthOnly && !showTraditionalLogin + ? "Use one of the options below to sign in." + : "Use your username and password to continue."} +

+ + {effectiveOAuthOnly && !showTraditionalLogin && ( +
+ +
+ +
-
- )} - - {(!effectiveOAuthOnly || showTraditionalLogin) && ( - -
- - -
- setShowPassword((v) => !v)} - className="rounded border-zinc-300 text-primary focus:ring-primary/30 dark:border-zinc-600" + )} + + {(!effectiveOAuthOnly || showTraditionalLogin) && ( + + + - -
-
-
- - Forgot password? - -

setMode("signup")} className="text-sm text-zinc-500 dark:text-zinc-400 transition-colors hover:text-primary/80 mt-1 cursor-pointer"> - Are you new? -

+ +
+ setShowPassword((v) => !v)} + className="rounded border-zinc-300 text-primary focus:ring-primary/30 dark:border-zinc-600" + /> +
- - - Sign in - -
- - {(isRobloxOAuth || isDiscordOAuth || isGoogleOAuth) && !effectiveOAuthOnly && ( +
+
+ + Forgot password? + +

setMode("signup")} + className="text-sm text-zinc-500 dark:text-zinc-400 transition-colors hover:text-primary/80 mt-1 cursor-pointer" + > + Are you new? +

+
+ + + Sign in + +
+ + {(isRobloxOAuth || isDiscordOAuth || isGoogleOAuth) && + !effectiveOAuthOnly && ( + <> + {divider} + + + )} + + {effectiveOAuthOnly && showTraditionalLogin && ( +
+ +
+ )} + + + )} + + )} + + {mode === "signup" && ( + <> + {signupStep === 0 && ( + <> +

+ Create an account +

+

+ Choose a username to get started. +

+ {!effectiveOAuthOnly && ( + +
{ + e.preventDefault(); + const username = getSignupValues("username"); + if (!username) return; + setLoading(true); + try { + const { data } = await axios.post( + "/api/auth/signup/preview", + { username }, + ); + setSignupThumbnail(data.thumbnail || ""); + setSignupDisplayName( + data.displayName || username, + ); + setSignupStep(1); + } catch (err: any) { + setErrSignup("username", { + type: "custom", + message: + err?.response?.data?.error || + "Something went wrong", + }); + } finally { + setLoading(false); + } + }} + className="mt-6 space-y-1" + noValidate + > + + {usernameCheckLoading && ( +

+ Checking username... +

+ )} + {!usernameCheckLoading && + usernameAvailable === true && ( +

+ Username is available +

+ )} +
+ + Continue + +
+
+
+ )} + {(isRobloxOAuth || isDiscordOAuth || isGoogleOAuth) && ( <> - {divider} + {!effectiveOAuthOnly && divider} )} - - {effectiveOAuthOnly && showTraditionalLogin && ( -
- + + )} + + {signupStep === 1 && ( + <> +
+
+ {signupThumbnail ? ( +
+ +
+ ) : ( +
+ ? +
+ )}
- )} - - - )} - - )} - - {mode === "signup" && ( - <> - {signupStep === 0 && ( - <> -

Create an account

-

Choose a username to get started.

- {!effectiveOAuthOnly && ( - -
{ - e.preventDefault(); - const username = getSignupValues("username"); - if (!username) return; - setLoading(true); - try { - const { data } = await axios.post("/api/auth/signup/preview", { username }); - setSignupThumbnail(data.thumbnail || ""); - setSignupDisplayName(data.displayName || username); - setSignupStep(1); - } catch (err: any) { - setErrSignup("username", { type: "custom", message: err?.response?.data?.error || "Something went wrong" }); - } finally { - setLoading(false); - } - }} className="mt-6 space-y-1" noValidate> - - {usernameCheckLoading &&

Checking username...

} - {!usernameCheckLoading && usernameAvailable === true && ( -

Username is available

+
+

+ Is{" "} + + {signupDisplayName || + getSignupValues("username") || + "this user"} + {" "} + correct? +

+

+ Confirm this is your Roblox account, then choose a + password. +

+
+
+
+ + setSignupStep(2)} + disabled={loading} + > + Yes, continue + +
+ + )} + + {signupStep === 2 && ( + <> +

+ Set a password +

+

+ Choose a secure password for your account. +

+ + + + + value === getSignupValues("password") || + "Passwords must match", + })} + /> +
+ Continue
+ {(isRobloxOAuth || + isDiscordOAuth || + isGoogleOAuth) && ( + <> + {divider} + + + )} +

+ Don't share your password. Don't use the + same password as your Roblox account. +

- )} - {(isRobloxOAuth || isDiscordOAuth || isGoogleOAuth) && ( - <> - {!effectiveOAuthOnly && divider} - - - )} - - )} - - {signupStep === 1 && ( - <> -
-
- {signupThumbnail ? ( -
- -
- ) : ( -
?
- )} -
-
-

- Is {signupDisplayName || getSignupValues("username") || "this user"} correct? -

-

Confirm this is your Roblox account, then choose a password.

-
-
-
- - setSignupStep(2)} disabled={loading}> - Yes, continue - -
- - )} - - {signupStep === 2 && ( - <> -

Set a password

-

Choose a secure password for your account.

- -
- - value === getSignupValues("password") || "Passwords must match", - })} /> -
- - - Continue - -
- {(isRobloxOAuth || isDiscordOAuth || isGoogleOAuth) && ( - <> - {divider} - - - )} -

- Don't share your password. Don't use the same password as your Roblox account. + + )} + + {signupStep === 3 && ( + <> +

+ Verify your account +

+

+ Paste this code into your Roblox profile bio, then + click Verify. +

+

{ + navigator.clipboard.writeText(verificationCode); + toast.success( + "Verification code copied to clipboard", + ); + }} + > + {verificationCode} +

+
    +
  • Go to your Roblox profile
  • +
  • Click "Edit Profile"
  • +
  • Paste the code into your Bio / About section
  • +
  • Save and click Verify below
  • +
+ {verificationError && ( +

+ {verificationError}

- -
- - )} - - {signupStep === 3 && ( - <> -

Verify your account

-

- Paste this code into your Roblox profile bio, then click Verify. -

-

{navigator.clipboard.writeText(verificationCode); toast.success("Verification code copied to clipboard")}} - > - {verificationCode} -

-
    -
  • Go to your Roblox profile
  • -
  • Click "Edit Profile"
  • -
  • Paste the code into your Bio / About section
  • -
  • Save and click Verify below
  • -
- {verificationError &&

{verificationError}

} -
- - - Verify - -
- - )} - - )} + )} +
+ + + Verify + +
+ + )} + + )}
-
- setShowCopyright(false)} className="relative z-50"> -