don't send a verification email during sign in if no match (#1999)
* don't send verification email on signin if there's no matching user, update email.js message * conditional magic code message; signup/signin button * unnecessary useCallback * switch to cookie parsing lib --------- Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									a669ec832b
								
							
						
					
					
						commit
						dbbd9477fd
					
				@ -223,7 +223,7 @@ async function nostrEventAuth (event) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {import('next-auth/providers').Provider[]} */
 | 
					/** @type {import('next-auth/providers').Provider[]} */
 | 
				
			||||||
const getProviders = res => [
 | 
					const getProviders = (req, res) => [
 | 
				
			||||||
  CredentialsProvider({
 | 
					  CredentialsProvider({
 | 
				
			||||||
    id: 'lightning',
 | 
					    id: 'lightning',
 | 
				
			||||||
    name: 'Lightning',
 | 
					    name: 'Lightning',
 | 
				
			||||||
@ -275,14 +275,14 @@ const getProviders = res => [
 | 
				
			|||||||
    from: process.env.LOGIN_EMAIL_FROM,
 | 
					    from: process.env.LOGIN_EMAIL_FROM,
 | 
				
			||||||
    maxAge: 5 * 60, // expires in 5 minutes
 | 
					    maxAge: 5 * 60, // expires in 5 minutes
 | 
				
			||||||
    generateVerificationToken: generateRandomString,
 | 
					    generateVerificationToken: generateRandomString,
 | 
				
			||||||
    sendVerificationRequest
 | 
					    sendVerificationRequest: (...args) => sendVerificationRequest(...args, req)
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @returns {import('next-auth').AuthOptions} */
 | 
					/** @returns {import('next-auth').AuthOptions} */
 | 
				
			||||||
export const getAuthOptions = (req, res) => ({
 | 
					export const getAuthOptions = (req, res) => ({
 | 
				
			||||||
  callbacks: getCallbacks(req, res),
 | 
					  callbacks: getCallbacks(req, res),
 | 
				
			||||||
  providers: getProviders(res),
 | 
					  providers: getProviders(req, res),
 | 
				
			||||||
  adapter: {
 | 
					  adapter: {
 | 
				
			||||||
    ...PrismaAdapter(prisma),
 | 
					    ...PrismaAdapter(prisma),
 | 
				
			||||||
    createUser: data => {
 | 
					    createUser: data => {
 | 
				
			||||||
@ -421,7 +421,7 @@ async function sendVerificationRequest ({
 | 
				
			|||||||
  url,
 | 
					  url,
 | 
				
			||||||
  token,
 | 
					  token,
 | 
				
			||||||
  provider
 | 
					  provider
 | 
				
			||||||
}) {
 | 
					}, req) {
 | 
				
			||||||
  let user = await prisma.user.findUnique({
 | 
					  let user = await prisma.user.findUnique({
 | 
				
			||||||
    where: {
 | 
					    where: {
 | 
				
			||||||
      // Look for the user by hashed email
 | 
					      // Look for the user by hashed email
 | 
				
			||||||
@ -443,6 +443,11 @@ async function sendVerificationRequest ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const site = new URL(url).host
 | 
					    const site = new URL(url).host
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // if we're trying to sign in but no user was found, resolve the promise
 | 
				
			||||||
 | 
					    if (req.cookies.signin && !user) {
 | 
				
			||||||
 | 
					      return resolve()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    nodemailer.createTransport(server).sendMail(
 | 
					    nodemailer.createTransport(server).sendMail(
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        to: email,
 | 
					        to: email,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import Image from 'react-bootstrap/Image'
 | 
					import Image from 'react-bootstrap/Image'
 | 
				
			||||||
 | 
					import * as cookie from 'cookie'
 | 
				
			||||||
import { StaticLayout } from '@/components/layout'
 | 
					import { StaticLayout } from '@/components/layout'
 | 
				
			||||||
import { getGetServerSideProps } from '@/api/ssrApollo'
 | 
					import { getGetServerSideProps } from '@/api/ssrApollo'
 | 
				
			||||||
import { useRouter } from 'next/router'
 | 
					import { useRouter } from 'next/router'
 | 
				
			||||||
@ -12,8 +13,10 @@ export const getServerSideProps = getGetServerSideProps({ query: null })
 | 
				
			|||||||
export default function Email () {
 | 
					export default function Email () {
 | 
				
			||||||
  const router = useRouter()
 | 
					  const router = useRouter()
 | 
				
			||||||
  const [callback, setCallback] = useState(null) // callback.email, callback.callbackUrl
 | 
					  const [callback, setCallback] = useState(null) // callback.email, callback.callbackUrl
 | 
				
			||||||
 | 
					  const [signin, setSignin] = useState(false)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  useEffect(() => {
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    setSignin(!!cookie.parse(document.cookie).signin)
 | 
				
			||||||
    setCallback(JSON.parse(window.sessionStorage.getItem('callback')))
 | 
					    setCallback(JSON.parse(window.sessionStorage.getItem('callback')))
 | 
				
			||||||
  }, [])
 | 
					  }, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,6 +30,13 @@ export default function Email () {
 | 
				
			|||||||
    router.push(url)
 | 
					    router.push(url)
 | 
				
			||||||
  }, [callback, router])
 | 
					  }, [callback, router])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const buildMessage = () => {
 | 
				
			||||||
 | 
					    const email = callback?.email || 'your email address'
 | 
				
			||||||
 | 
					    return signin
 | 
				
			||||||
 | 
					      ? `if there's a match, a magic code will be sent to ${email}`
 | 
				
			||||||
 | 
					      : `a magic code has been sent to ${email}`
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <StaticLayout>
 | 
					    <StaticLayout>
 | 
				
			||||||
      <div className='p-4 text-center'>
 | 
					      <div className='p-4 text-center'>
 | 
				
			||||||
@ -35,14 +45,14 @@ export default function Email () {
 | 
				
			|||||||
          <Image className='rounded-1 shadow-sm' width='640' height='302' src={`${process.env.NEXT_PUBLIC_ASSET_PREFIX}/cowboy-saloon.gif`} fluid />
 | 
					          <Image className='rounded-1 shadow-sm' width='640' height='302' src={`${process.env.NEXT_PUBLIC_ASSET_PREFIX}/cowboy-saloon.gif`} fluid />
 | 
				
			||||||
        </video>
 | 
					        </video>
 | 
				
			||||||
        <h2 className='pt-4'>Check your email</h2>
 | 
					        <h2 className='pt-4'>Check your email</h2>
 | 
				
			||||||
        <h4 className='text-muted pt-2 pb-4'>a magic code has been sent to {callback ? callback.email : 'your email address'}</h4>
 | 
					        <h4 className='text-muted pt-2 pb-4'>{buildMessage()}</h4>
 | 
				
			||||||
        <MagicCodeForm onSubmit={(token) => pushCallback(token)} disabled={!callback} />
 | 
					        <MagicCodeForm onSubmit={(token) => pushCallback(token)} disabled={!callback} signin={signin} />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </StaticLayout>
 | 
					    </StaticLayout>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const MagicCodeForm = ({ onSubmit, disabled }) => {
 | 
					export const MagicCodeForm = ({ onSubmit, disabled, signin }) => {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Form
 | 
					    <Form
 | 
				
			||||||
      initial={{
 | 
					      initial={{
 | 
				
			||||||
@ -64,7 +74,7 @@ export const MagicCodeForm = ({ onSubmit, disabled }) => {
 | 
				
			|||||||
        hideError // hide error message on every input, allow custom error message
 | 
					        hideError // hide error message on every input, allow custom error message
 | 
				
			||||||
        disabled={disabled} // disable the form if no callback is provided
 | 
					        disabled={disabled} // disable the form if no callback is provided
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
      <SubmitButton variant='primary' className='px-4' disabled={disabled}>login</SubmitButton>
 | 
					      <SubmitButton variant='primary' className='px-4' disabled={disabled}>{signin ? 'login' : 'signup'}</SubmitButton>
 | 
				
			||||||
    </Form>
 | 
					    </Form>
 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user