mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 04:40:05 +01:00
120 lines
4.5 KiB
TypeScript
120 lines
4.5 KiB
TypeScript
import { useEffect, useMemo } from "react"
|
|
import { authStore, type TokenPair } from "@/auth/store.ts"
|
|
import { API_BASE } from "@/sdkClient.ts"
|
|
import { useLocation, useNavigate } from "react-router-dom"
|
|
|
|
import { cn } from "@/lib/utils.ts"
|
|
import { Button } from "@/components/ui/button.tsx"
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
|
|
|
function openPopup(url: string, name = "gsot-auth", w = 520, h = 640) {
|
|
const y = window.top!.outerHeight / 2 + window.top!.screenY - h / 2
|
|
const x = window.top!.outerWidth / 2 + window.top!.screenX - w / 2
|
|
return window.open(
|
|
url,
|
|
name,
|
|
`toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=${w},height=${h},top=${y},left=${x}`
|
|
)
|
|
}
|
|
|
|
async function startAuth(provider: "google" | "github") {
|
|
const params = new URLSearchParams({
|
|
mode: "spa",
|
|
origin: window.location.origin,
|
|
})
|
|
const res = await fetch(`${API_BASE}/auth/${provider}/start?` + params, {
|
|
method: "POST",
|
|
})
|
|
if (!res.ok) throw new Error("Failed to start auth")
|
|
const data = await res.json()
|
|
return data.auth_url as string
|
|
}
|
|
|
|
export const Login = () => {
|
|
const navigate = useNavigate()
|
|
const loc = useLocation()
|
|
|
|
const to = useMemo(() => {
|
|
const p = new URLSearchParams(loc.search).get("to") || "/me"
|
|
try {
|
|
// prevent absolute URLs & open redirects
|
|
const url = new URL(p, window.location.origin)
|
|
return url.origin === window.location.origin ? url.pathname + url.search : "/me"
|
|
} catch {
|
|
return "/me"
|
|
}
|
|
}, [loc.search])
|
|
|
|
useEffect(() => {
|
|
if (authStore.get()?.access_token) {
|
|
navigate(to, { replace: true })
|
|
}
|
|
}, [navigate, to])
|
|
|
|
useEffect(() => {
|
|
const onMsg = (ev: MessageEvent) => {
|
|
const okType = typeof ev.data === "object" && ev.data?.type === "autoglue:auth"
|
|
if (!okType) return
|
|
const tokens: TokenPair = ev.data.payload
|
|
authStore.set(tokens)
|
|
navigate(to, { replace: true })
|
|
}
|
|
window.addEventListener("message", onMsg)
|
|
return () => window.removeEventListener("message", onMsg)
|
|
}, [navigate, to])
|
|
|
|
const login = async (provider: "google" | "github") => {
|
|
const url = await startAuth(provider)
|
|
const win = openPopup(url)
|
|
if (!win) alert("Please allow popups to sign in.")
|
|
}
|
|
|
|
return (
|
|
<div className="mx-auto flex items-center justify-center p-4">
|
|
<Card className="w-full max-w-md">
|
|
<CardHeader>
|
|
<CardTitle className="text-lg md:text-xl">Sign In</CardTitle>
|
|
<CardDescription className="text-xs md:text-sm">
|
|
Continue with a provider below to access your account.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
|
|
<CardContent>
|
|
<div className="grid gap-4">
|
|
<div className={cn("flex w-full items-center gap-2", "flex-col justify-between")}>
|
|
<Button variant="outline" className="w-full gap-2" onClick={() => login("google")}>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
width="0.98em"
|
|
height="1em"
|
|
viewBox="0 0 256 262"
|
|
aria-hidden="true"
|
|
focusable="false"
|
|
>
|
|
<path
|
|
fill="#4285F4"
|
|
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
|
|
></path>
|
|
<path
|
|
fill="#34A853"
|
|
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
|
|
></path>
|
|
<path
|
|
fill="#FBBC05"
|
|
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
|
|
></path>
|
|
<path
|
|
fill="#EB4335"
|
|
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
|
|
></path>
|
|
</svg>
|
|
Sign in with Google
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|