mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
More auth related sentry whitelist errors (#27481)
* More auth related sentry whitelist errors * Make pretty
This commit is contained in:
1 parent
45066f6b65
commit
d80befbae2
6 files changed
+61
-51
No files matched your search
@@ -1,5 +1,4 @@
|
||||
import HCaptcha from '@hcaptcha/react-hcaptcha'
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
@@ -9,8 +8,6 @@ import { useResetPasswordMutation } from 'data/misc/reset-password-mutation'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
|
||||
const WHITELIST_ERRORS = ['email must be an email']
|
||||
|
||||
const forgotPasswordSchema = object({
|
||||
email: string().email('Must be a valid email').required('Email is required'),
|
||||
})
|
||||
@@ -31,10 +28,6 @@ const ForgotPasswordForm = () => {
|
||||
setCaptchaToken(null)
|
||||
captchaRef.current?.resetCaptcha()
|
||||
toast.error(`Failed to send reset email: ${error.message}`)
|
||||
|
||||
if (!WHITELIST_ERRORS.some((e) => error.message.includes(e))) {
|
||||
Sentry.captureMessage('[CRITICAL] Failed to send reset password email: ' + error.message)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import type { AuthError } from '@supabase/auth-js'
|
||||
import type { Factor } from '@supabase/supabase-js'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { Lock } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import { object, string } from 'yup'
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
|
||||
import { useTelemetryProps } from 'common'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
@@ -16,7 +14,7 @@ import { useMfaListFactorsQuery } from 'data/profile/mfa-list-factors-query'
|
||||
import { useSignOut } from 'lib/auth'
|
||||
import { getReturnToPath } from 'lib/gotrue'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { Button, Form, IconLock, Input } from 'ui'
|
||||
import { Button, Form, Input } from 'ui'
|
||||
|
||||
const signInSchema = object({
|
||||
code: string().required('MFA Code is required'),
|
||||
@@ -36,7 +34,21 @@ const SignInMfaForm = () => {
|
||||
isSuccess: isSuccessFactors,
|
||||
isLoading: isLoadingFactors,
|
||||
} = useMfaListFactorsQuery()
|
||||
const { mutate: mfaChallengeAndVerify, isLoading, isSuccess } = useMfaChallengeAndVerifyMutation()
|
||||
const {
|
||||
mutate: mfaChallengeAndVerify,
|
||||
isLoading: isVerifying,
|
||||
isSuccess,
|
||||
} = useMfaChallengeAndVerifyMutation({
|
||||
onSuccess: async () => {
|
||||
Telemetry.sendEvent(
|
||||
{ category: 'account', action: 'sign_in', label: '' },
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
await queryClient.resetQueries()
|
||||
router.push(getReturnToPath())
|
||||
},
|
||||
})
|
||||
|
||||
const onClickLogout = async () => {
|
||||
await signOut()
|
||||
@@ -44,27 +56,8 @@ const SignInMfaForm = () => {
|
||||
}
|
||||
|
||||
const onSignIn = async ({ code }: { code: string }) => {
|
||||
const toastId = toast.loading('Signing in...')
|
||||
if (selectedFactor) {
|
||||
mfaChallengeAndVerify(
|
||||
{ factorId: selectedFactor.id, code, refreshFactors: false },
|
||||
{
|
||||
onSuccess: async () => {
|
||||
toast.success('Signed in successfully!', { id: toastId })
|
||||
Telemetry.sendEvent(
|
||||
{ category: 'account', action: 'sign_in', label: '' },
|
||||
telemetryProps,
|
||||
router
|
||||
)
|
||||
await queryClient.resetQueries()
|
||||
router.push(getReturnToPath())
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(`Failed to sign in: ${(error as AuthError).message}`, { id: toastId })
|
||||
Sentry.captureMessage('[CRITICAL] Failed to sign in via MFA: ' + error.message)
|
||||
},
|
||||
}
|
||||
)
|
||||
mfaChallengeAndVerify({ factorId: selectedFactor.id, code, refreshFactors: false })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +95,9 @@ const SignInMfaForm = () => {
|
||||
name="code"
|
||||
type="text"
|
||||
autoFocus
|
||||
icon={<IconLock />}
|
||||
icon={<Lock />}
|
||||
placeholder="XXXXXX"
|
||||
disabled={isLoading}
|
||||
disabled={isVerifying}
|
||||
autoComplete="off"
|
||||
spellCheck="false"
|
||||
autoCapitalize="none"
|
||||
@@ -121,7 +114,7 @@ const SignInMfaForm = () => {
|
||||
block
|
||||
type="outline"
|
||||
size="large"
|
||||
disabled={isLoading || isSuccess}
|
||||
disabled={isVerifying || isSuccess}
|
||||
onClick={onClickLogout}
|
||||
className="opacity-80 hover:opacity-100 transition"
|
||||
>
|
||||
@@ -132,10 +125,10 @@ const SignInMfaForm = () => {
|
||||
form="sign-in-mfa-form"
|
||||
htmlType="submit"
|
||||
size="large"
|
||||
disabled={isLoading || isSuccess}
|
||||
loading={isLoading || isSuccess}
|
||||
disabled={isVerifying || isSuccess}
|
||||
loading={isVerifying || isSuccess}
|
||||
>
|
||||
{isLoading ? 'Verifying' : isSuccess ? 'Signing in' : 'Verify'}
|
||||
{isVerifying ? 'Verifying' : isSuccess ? 'Signing in' : 'Verify'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -163,9 +156,9 @@ const SignInMfaForm = () => {
|
||||
)}
|
||||
<li>
|
||||
<Link
|
||||
href="/support/new?subject=Unable+to+sign+in+via+MFA&category=Login_issues"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="/support/new?subject=Unable+to+sign+in+via+MFA&category=Login_issues"
|
||||
className="text-sm transition text-foreground-light hover:text-foreground"
|
||||
>
|
||||
Reach out to us via support
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import HCaptcha from '@hcaptcha/react-hcaptcha'
|
||||
import { CheckCircle } from 'lucide-react'
|
||||
import { CheckCircle, Eye, EyeOff } from 'lucide-react'
|
||||
import { useRef, useState } from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import * as yup from 'yup'
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
|
||||
import { useSignUpMutation } from 'data/misc/signup-mutation'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
@@ -14,14 +13,10 @@ import {
|
||||
Alert_Shadcn_,
|
||||
Button,
|
||||
Form,
|
||||
IconEye,
|
||||
IconEyeOff,
|
||||
Input,
|
||||
} from 'ui'
|
||||
import PasswordConditionsHelper from './PasswordConditionsHelper'
|
||||
|
||||
const WHITELIST_ERRORS = ['A user with this email already exists']
|
||||
|
||||
const signUpSchema = passwordSchema.shape({
|
||||
email: yup.string().email().required().label('Email'),
|
||||
})
|
||||
@@ -42,10 +37,6 @@ const SignUpForm = () => {
|
||||
setCaptchaToken(null)
|
||||
captchaRef.current?.resetCaptcha()
|
||||
toast.error(`Failed to sign up: ${error.message}`)
|
||||
|
||||
if (!WHITELIST_ERRORS.includes(error.message)) {
|
||||
Sentry.captureMessage('[CRITICAL] Failed to sign up: ' + error.message)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@@ -118,7 +109,7 @@ const SignUpForm = () => {
|
||||
onFocus={() => setShowConditions(true)}
|
||||
actions={
|
||||
<Button
|
||||
icon={passwordHidden ? <IconEye /> : <IconEyeOff />}
|
||||
icon={passwordHidden ? <Eye /> : <EyeOff />}
|
||||
type="default"
|
||||
className="!mr-1"
|
||||
onClick={() => setPasswordHidden((prev) => !prev)}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import { useMutation, UseMutationOptions } from '@tanstack/react-query'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { handleError, post } from 'data/fetchers'
|
||||
import type { ResponseError } from 'types'
|
||||
|
||||
const WHITELIST_ERRORS = ['email must be an email']
|
||||
|
||||
export type ResetPasswordVariables = {
|
||||
email: string
|
||||
hcaptchaToken: string | null
|
||||
@@ -42,6 +45,9 @@ export const useResetPasswordMutation = ({
|
||||
} else {
|
||||
onError(data, variables, context)
|
||||
}
|
||||
if (!WHITELIST_ERRORS.some((error) => data.message.includes(error))) {
|
||||
Sentry.captureMessage('[CRITICAL] Failed to send reset password email: ' + data.message)
|
||||
}
|
||||
},
|
||||
...options,
|
||||
}
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import { useMutation, UseMutationOptions } from '@tanstack/react-query'
|
||||
import { toast } from 'react-hot-toast'
|
||||
|
||||
import { handleError, post } from 'data/fetchers'
|
||||
import type { ResponseError } from 'types'
|
||||
|
||||
const WHITELIST_ERRORS = [
|
||||
'A user with this email already exists',
|
||||
'Password should contain at least one character of each',
|
||||
'You attempted to send email to an inactive recipient',
|
||||
'email must be an email',
|
||||
]
|
||||
|
||||
export type SignUpVariables = {
|
||||
email: string
|
||||
password: string
|
||||
@@ -38,6 +46,9 @@ export const useSignUpMutation = ({
|
||||
} else {
|
||||
onError(data, variables, context)
|
||||
}
|
||||
if (!WHITELIST_ERRORS.some((error) => data.message.includes(error))) {
|
||||
Sentry.captureMessage('[CRITICAL] Failed to sign up: ' + data.message)
|
||||
}
|
||||
},
|
||||
...options,
|
||||
})
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import * as Sentry from '@sentry/nextjs'
|
||||
import type { AuthMFAVerifyResponse, MFAChallengeAndVerifyParams } from '@supabase/supabase-js'
|
||||
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
|
||||
import { UseMutationOptions, useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import toast from 'react-hot-toast'
|
||||
|
||||
import { auth } from 'lib/gotrue'
|
||||
import { profileKeys } from './keys'
|
||||
|
||||
const WHITELIST_ERRORS = ['Invalid TOTP code entered']
|
||||
|
||||
interface MFAChallengeAndVerifyVariables extends MFAChallengeAndVerifyParams {
|
||||
refreshFactors?: boolean
|
||||
}
|
||||
@@ -18,6 +23,7 @@ type CustomMFAVerifyError = NonNullable<AuthMFAVerifyResponse['error']>
|
||||
|
||||
export const useMfaChallengeAndVerifyMutation = ({
|
||||
onSuccess,
|
||||
onError,
|
||||
...options
|
||||
}: Omit<
|
||||
UseMutationOptions<CustomMFAVerifyResponse, CustomMFAVerifyError, MFAChallengeAndVerifyVariables>,
|
||||
@@ -42,6 +48,16 @@ export const useMfaChallengeAndVerifyMutation = ({
|
||||
|
||||
await onSuccess?.(data, variables, context)
|
||||
},
|
||||
async onError(data, variables, context) {
|
||||
if (onError === undefined) {
|
||||
toast.error(`Failed to sign in: ${data.message}`)
|
||||
} else {
|
||||
onError(data, variables, context)
|
||||
}
|
||||
if (!WHITELIST_ERRORS.some((error) => data.message.includes(error))) {
|
||||
Sentry.captureMessage('[CRITICAL] Failed to sign in via MFA: ' + data.message)
|
||||
}
|
||||
},
|
||||
...options,
|
||||
}
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user