mirror of
https://github.com/supabase/supabase.git
synced 2026-10-07 02:15:05 +03:00
fixes vercel and database.new integrations
by having both ?next= (external) and ?redirectTo= (internal)
This commit is contained in:
1 parent
ec9cd56e27
commit
e7b0f5b823
6 files changed
+105
-26
No files matched your search
@@ -1,8 +1,8 @@
|
||||
import HCaptcha from '@hcaptcha/react-hcaptcha'
|
||||
import { useStore } from 'hooks'
|
||||
import { auth, getNextPath } from 'lib/gotrue'
|
||||
import { usePushNext } from 'hooks/misc/useAutoAuthRedirect'
|
||||
import { auth } from 'lib/gotrue'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useRef, useState } from 'react'
|
||||
import { useSWRConfig } from 'swr'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
@@ -15,7 +15,7 @@ const signInSchema = object({
|
||||
|
||||
const SignInForm = () => {
|
||||
const { ui } = useStore()
|
||||
const router = useRouter()
|
||||
const pushNext = usePushNext()
|
||||
const { cache } = useSWRConfig()
|
||||
|
||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null)
|
||||
@@ -50,7 +50,7 @@ const SignInForm = () => {
|
||||
// @ts-ignore
|
||||
cache.clear()
|
||||
|
||||
await router.push(getNextPath())
|
||||
await pushNext()
|
||||
} else {
|
||||
setCaptchaToken(null)
|
||||
captchaRef.current?.resetCaptcha()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { auth, getNextPath } from 'lib/gotrue'
|
||||
import { auth, getReturnToPath } from 'lib/gotrue'
|
||||
import { Button, IconGitHub } from 'ui'
|
||||
|
||||
const SignInWithGitHub = () => {
|
||||
@@ -11,7 +11,7 @@ const SignInWithGitHub = () => {
|
||||
process.env.NEXT_PUBLIC_VERCEL_ENV === 'preview'
|
||||
? process.env.NEXT_PUBLIC_VERCEL_URL
|
||||
: process.env.NEXT_PUBLIC_SITE_URL
|
||||
}${getNextPath()}`,
|
||||
}${getReturnToPath()}`,
|
||||
},
|
||||
})
|
||||
if (error) throw error
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import { useStore } from 'hooks'
|
||||
import { getNextPath, STORAGE_KEY } from 'lib/gotrue'
|
||||
import { usePushNext } from 'hooks/misc/useAutoAuthRedirect'
|
||||
import { auth, getReturnToPath, STORAGE_KEY } from 'lib/gotrue'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import Head from 'next/head'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { PropsWithChildren, useEffect, useState } from 'react'
|
||||
import { tweets } from 'shared-data'
|
||||
import { useSWRConfig } from 'swr'
|
||||
import { Button, IconFileText } from 'ui'
|
||||
|
||||
type SignInLayoutProps = {
|
||||
@@ -22,9 +24,44 @@ const SignInLayout = ({
|
||||
logoLinkToMarketingSite = false,
|
||||
children,
|
||||
}: PropsWithChildren<SignInLayoutProps>) => {
|
||||
const pushNext = usePushNext()
|
||||
const { ui } = useStore()
|
||||
const { cache } = useSWRConfig()
|
||||
const { theme } = ui
|
||||
|
||||
useEffect(() => {
|
||||
const searchParams = new URLSearchParams(location.search)
|
||||
const hasReturnTo = searchParams.has('returnTo')
|
||||
const hasNext = searchParams.has('next')
|
||||
const shouldRedirect = !hasReturnTo && !hasNext
|
||||
|
||||
if (!shouldRedirect) {
|
||||
// If there's a returnTo or next, then this redirect will be handled by useAutoAuthRedirect() in _app.tsx
|
||||
return
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
const { error } = await auth.initialize()
|
||||
|
||||
if (error) {
|
||||
// if there was a problem signing in via the url, don't redirect
|
||||
return
|
||||
}
|
||||
|
||||
const {
|
||||
data: { session },
|
||||
} = await auth.getSession()
|
||||
|
||||
if (session) {
|
||||
// .clear() does actually exist on the cache object, but it's not in the types 🤦🏻
|
||||
// @ts-ignore
|
||||
cache.clear()
|
||||
|
||||
await pushNext()
|
||||
}
|
||||
})()
|
||||
}, [])
|
||||
|
||||
const [quote, setQuote] = useState<{
|
||||
text: string
|
||||
url: string
|
||||
@@ -43,7 +80,7 @@ const SignInLayout = ({
|
||||
<Head>
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window._getNextPath = ${getNextPath.toString()};if (localStorage.getItem('${STORAGE_KEY}')) {location.replace(window._getNextPath())}`,
|
||||
__html: `window._getReturnToPath = ${getReturnToPath.toString()};if (localStorage.getItem('${STORAGE_KEY}') && !(new URLSearchParams(location.search).has('next'))) {location.replace(window._getReturnToPath())}`,
|
||||
}}
|
||||
/>
|
||||
</Head>
|
||||
|
||||
@@ -1,17 +1,64 @@
|
||||
import { auth, getNextPath } from 'lib/gotrue'
|
||||
import { auth, getReturnToPath } from 'lib/gotrue'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect } from 'react'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import { useSWRConfig } from 'swr'
|
||||
|
||||
function useAutoAuthRedirect() {
|
||||
export function usePushNext() {
|
||||
const router = useRouter()
|
||||
|
||||
return useCallback(
|
||||
async () => {
|
||||
const searchParams = new URLSearchParams(location.search)
|
||||
|
||||
const hasNext = searchParams.has('next')
|
||||
|
||||
// preference the next param, as it's used for integration redirects
|
||||
if (hasNext) {
|
||||
const next = searchParams.get('next')!
|
||||
|
||||
// vercel integration
|
||||
const isVercelIntegration = next.includes('https://vercel.com')
|
||||
if (isVercelIntegration) {
|
||||
searchParams.delete('returnTo')
|
||||
|
||||
return await router.push(`/vercel/integrate?${searchParams.toString()}`)
|
||||
}
|
||||
|
||||
// database.new integration
|
||||
if (next === 'new-project') {
|
||||
searchParams.delete('next')
|
||||
searchParams.delete('returnTo')
|
||||
const remainingSearchParams = searchParams.toString()
|
||||
|
||||
return await router.push(
|
||||
'/new/new-project' + (remainingSearchParams ? `?${remainingSearchParams}` : '')
|
||||
)
|
||||
}
|
||||
|
||||
return await router.push(
|
||||
next + (searchParams.toString() ? `?${searchParams.toString()}` : '')
|
||||
)
|
||||
}
|
||||
|
||||
return await router.push(getReturnToPath())
|
||||
},
|
||||
// watch params so router.query will get updated
|
||||
[router.query]
|
||||
)
|
||||
}
|
||||
|
||||
function useAutoAuthRedirect() {
|
||||
const pushNext = usePushNext()
|
||||
const { cache } = useSWRConfig()
|
||||
|
||||
useEffect(() => {
|
||||
const returnTo = new URLSearchParams(location.search).get('next')
|
||||
const searchParams = new URLSearchParams(location.search)
|
||||
const hasReturnTo = searchParams.has('returnTo')
|
||||
const hasNext = searchParams.has('next')
|
||||
const shouldRedirect = hasReturnTo || hasNext
|
||||
|
||||
if (!returnTo) {
|
||||
// If there's no returnTo, then we don't need to do anything
|
||||
if (!shouldRedirect) {
|
||||
// If there's no returnTo or next, then we don't need to do anything
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,7 +79,7 @@ function useAutoAuthRedirect() {
|
||||
// @ts-ignore
|
||||
cache.clear()
|
||||
|
||||
await router.push(getNextPath())
|
||||
await pushNext()
|
||||
}
|
||||
})()
|
||||
}, [])
|
||||
|
||||
@@ -2,7 +2,7 @@ import { ComponentType, useEffect } from 'react'
|
||||
import Head from 'next/head'
|
||||
import { NextRouter, useRouter } from 'next/router'
|
||||
|
||||
import { getNextPath, STORAGE_KEY } from 'lib/gotrue'
|
||||
import { getReturnToPath, STORAGE_KEY } from 'lib/gotrue'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useProfile, useStore, usePermissions } from 'hooks'
|
||||
import Error500 from '../../pages/500'
|
||||
@@ -86,7 +86,7 @@ export function withAuth<T>(
|
||||
to the login page if they are guaranteed (no token at all) to not be logged in. */}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `window._getNextPath = ${getNextPath.toString()};if (!localStorage.getItem('${STORAGE_KEY}') && !location.hash) {location.replace('/sign-in?next=' + window._getNextPath(location.pathname))}`,
|
||||
__html: `window._getReturnToPath = ${getReturnToPath.toString()};if (!localStorage.getItem('${STORAGE_KEY}') && !location.hash) {const searchParams = new URLSearchParams(location.search);searchParams.set('returnTo', location.pathname);location.replace('/sign-in' + '?' + searchParams.toString())}`,
|
||||
}}
|
||||
/>
|
||||
</Head>
|
||||
|
||||
@@ -40,18 +40,13 @@ export const getIdentity = (gotrueUser: User) => {
|
||||
|
||||
// NOTE: do not use any imports in this function,
|
||||
// as it is use standalone in the documents head
|
||||
export const getNextPath = (fallback = '/projects') => {
|
||||
export const getReturnToPath = (fallback = '/projects') => {
|
||||
const searchParams = new URLSearchParams(location.search)
|
||||
const returnTo = searchParams.get('next')
|
||||
let returnTo = searchParams.get('returnTo') ?? fallback
|
||||
|
||||
searchParams.delete('next')
|
||||
searchParams.delete('returnTo')
|
||||
|
||||
const next = returnTo ?? fallback
|
||||
const remainingSearchParams = searchParams.toString()
|
||||
|
||||
if (next === 'new-project') {
|
||||
return '/new/new-project' + (remainingSearchParams ? `?${remainingSearchParams}` : '')
|
||||
}
|
||||
|
||||
return next + (remainingSearchParams ? `?${remainingSearchParams}` : '')
|
||||
return returnTo + (remainingSearchParams ? `?${remainingSearchParams}` : '')
|
||||
}
|
||||
Reference in new issue
Block a user