Skip to content

Commit

Permalink
Merge pull request #119 from goodeats/108-prevent-new-users-after-dep…
Browse files Browse the repository at this point in the history
…loyment

prevent new users after deployment
  • Loading branch information
goodeats authored May 23, 2024
2 parents 72d5b6a + 85c5cef commit 05716dc
Show file tree
Hide file tree
Showing 61 changed files with 770 additions and 389 deletions.
16 changes: 8 additions & 8 deletions app/routes/_auth+/auth.$provider.callback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ afterEach(async () => {
await deleteGitHubUsers()
})

test('a new user goes to onboarding', async () => {
test.skip('a new user goes to onboarding', async () => {
const request = await setupRequest()
const response = await loader({ request, params: PARAMS, context: {} }).catch(
e => e,
)
expect(response).toHaveRedirect('/onboarding/github')
})

test('when auth fails, send the user to login with a toast', async () => {
test.skip('when auth fails, send the user to login with a toast', async () => {
consoleError.mockImplementation(() => {})
server.use(
http.post('https://github.com/login/oauth/access_token', async () => {
Expand All @@ -53,7 +53,7 @@ test('when auth fails, send the user to login with a toast', async () => {
expect(consoleError).toHaveBeenCalledTimes(1)
})

test('when a user is logged in, it creates the connection', async () => {
test.skip('when a user is logged in, it creates the connection', async () => {
const githubUser = await insertGitHubUser()
const session = await setupUser()
const request = await setupRequest({
Expand Down Expand Up @@ -82,7 +82,7 @@ test('when a user is logged in, it creates the connection', async () => {
).toBeTruthy()
})

test(`when a user is logged in and has already connected, it doesn't do anything and just redirects the user back to the connections page`, async () => {
test.skip(`when a user is logged in and has already connected, it doesn't do anything and just redirects the user back to the connections page`, async () => {
const session = await setupUser()
const githubUser = await insertGitHubUser()
await prisma.connection.create({
Expand All @@ -106,7 +106,7 @@ test(`when a user is logged in and has already connected, it doesn't do anything
)
})

test('when a user exists with the same email, create connection and make session', async () => {
test.skip('when a user exists with the same email, create connection and make session', async () => {
const githubUser = await insertGitHubUser()
const email = githubUser.primaryEmail.toLowerCase()
const { userId } = await setupUser({ ...createUser(), email })
Expand Down Expand Up @@ -137,7 +137,7 @@ test('when a user exists with the same email, create connection and make session
await expect(response).toHaveSessionForUser(userId)
})

test('gives an error if the account is already connected to another user', async () => {
test.skip('gives an error if the account is already connected to another user', async () => {
const githubUser = await insertGitHubUser()
await prisma.user.create({
data: {
Expand Down Expand Up @@ -167,7 +167,7 @@ test('gives an error if the account is already connected to another user', async
)
})

test('if a user is not logged in, but the connection exists, make a session', async () => {
test.skip('if a user is not logged in, but the connection exists, make a session', async () => {
const githubUser = await insertGitHubUser()
const { userId } = await setupUser()
await prisma.connection.create({
Expand All @@ -183,7 +183,7 @@ test('if a user is not logged in, but the connection exists, make a session', as
await expect(response).toHaveSessionForUser(userId)
})

test('if a user is not logged in, but the connection exists and they have enabled 2FA, send them to verify their 2FA and do not make a session', async () => {
test.skip('if a user is not logged in, but the connection exists and they have enabled 2FA, send them to verify their 2FA and do not make a session', async () => {
const githubUser = await insertGitHubUser()
const { userId } = await setupUser()
await prisma.connection.create({
Expand Down
311 changes: 147 additions & 164 deletions app/routes/_auth+/auth.$provider.callback.ts
Original file line number Diff line number Diff line change
@@ -1,179 +1,162 @@
import { redirect, type LoaderFunctionArgs } from '@remix-run/node'
import {
authenticator,
getSessionExpirationDate,
getUserId,
} from '#app/utils/auth.server.ts'
import { ProviderNameSchema, providerLabels } from '#app/utils/connections.tsx'
import { prisma } from '#app/utils/db.server.ts'
import { combineHeaders } from '#app/utils/misc.tsx'
import {
destroyRedirectToHeader,
getRedirectCookieValue,
} from '#app/utils/redirect-cookie.server.ts'
import {
createToastHeaders,
redirectWithToast,
} from '#app/utils/toast.server.ts'
import { verifySessionStorage } from '#app/utils/verification.server.ts'
import { handleNewSession } from './login.server.ts'
import {
onboardingEmailSessionKey,
prefilledProfileKey,
providerIdKey,
} from './onboarding_.$provider.tsx'
import { type LoaderFunctionArgs } from '@remix-run/node'
import { redirectWithToast } from '#app/utils/toast.server.ts'

const destroyRedirectTo = { 'set-cookie': destroyRedirectToHeader }
// const destroyRedirectTo = { 'set-cookie': destroyRedirectToHeader }

export async function loader({ request, params }: LoaderFunctionArgs) {
const providerName = ProviderNameSchema.parse(params.provider)
const redirectTo = getRedirectCookieValue(request)
const label = providerLabels[providerName]
return redirectWithToast('/', {
type: 'error',
title: 'Access Denied',
description: 'No new users at this time.',
})
// const providerName = ProviderNameSchema.parse(params.provider)
// const redirectTo = getRedirectCookieValue(request)
// const label = providerLabels[providerName]

const authResult = await authenticator
.authenticate(providerName, request, { throwOnError: true })
.then(
data => ({ success: true, data }) as const,
error => ({ success: false, error }) as const,
)
// const authResult = await authenticator
// .authenticate(providerName, request, { throwOnError: true })
// .then(
// data => ({ success: true, data }) as const,
// error => ({ success: false, error }) as const,
// )

if (!authResult.success) {
console.error(authResult.error)
throw await redirectWithToast(
'/login',
{
title: 'Auth Failed',
description: `There was an error authenticating with ${label}.`,
type: 'error',
},
{ headers: destroyRedirectTo },
)
}
// if (!authResult.success) {
// console.error(authResult.error)
// throw await redirectWithToast(
// '/login',
// {
// title: 'Auth Failed',
// description: `There was an error authenticating with ${label}.`,
// type: 'error',
// },
// { headers: destroyRedirectTo },
// )
// }

const { data: profile } = authResult
// const { data: profile } = authResult

const existingConnection = await prisma.connection.findUnique({
select: { userId: true },
where: {
providerName_providerId: { providerName, providerId: profile.id },
},
})
// const existingConnection = await prisma.connection.findUnique({
// select: { userId: true },
// where: {
// providerName_providerId: { providerName, providerId: profile.id },
// },
// })

const userId = await getUserId(request)
// const userId = await getUserId(request)

if (existingConnection && userId) {
if (existingConnection.userId === userId) {
return redirectWithToast(
'/settings/profile/connections',
{
title: 'Already Connected',
description: `Your "${profile.username}" ${label} account is already connected.`,
},
{ headers: destroyRedirectTo },
)
} else {
return redirectWithToast(
'/settings/profile/connections',
{
title: 'Already Connected',
description: `The "${profile.username}" ${label} account is already connected to another account.`,
},
{ headers: destroyRedirectTo },
)
}
}
// if (existingConnection && userId) {
// if (existingConnection.userId === userId) {
// return redirectWithToast(
// '/settings/profile/connections',
// {
// title: 'Already Connected',
// description: `Your "${profile.username}" ${label} account is already connected.`,
// },
// { headers: destroyRedirectTo },
// )
// } else {
// return redirectWithToast(
// '/settings/profile/connections',
// {
// title: 'Already Connected',
// description: `The "${profile.username}" ${label} account is already connected to another account.`,
// },
// { headers: destroyRedirectTo },
// )
// }
// }

// If we're already logged in, then link the account
if (userId) {
await prisma.connection.create({
data: {
providerName,
providerId: profile.id,
userId,
},
})
return redirectWithToast(
'/settings/profile/connections',
{
title: 'Connected',
type: 'success',
description: `Your "${profile.username}" ${label} account has been connected.`,
},
{ headers: destroyRedirectTo },
)
}
// // If we're already logged in, then link the account
// if (userId) {
// await prisma.connection.create({
// data: {
// providerName,
// providerId: profile.id,
// userId,
// },
// })
// return redirectWithToast(
// '/settings/profile/connections',
// {
// title: 'Connected',
// type: 'success',
// description: `Your "${profile.username}" ${label} account has been connected.`,
// },
// { headers: destroyRedirectTo },
// )
// }

// Connection exists already? Make a new session
if (existingConnection) {
return makeSession({ request, userId: existingConnection.userId })
}
// // Connection exists already? Make a new session
// if (existingConnection) {
// return makeSession({ request, userId: existingConnection.userId })
// }

// if the email matches a user in the db, then link the account and
// make a new session
const user = await prisma.user.findUnique({
select: { id: true },
where: { email: profile.email.toLowerCase() },
})
if (user) {
await prisma.connection.create({
data: {
providerName,
providerId: profile.id,
userId: user.id,
},
})
return makeSession(
{ request, userId: user.id },
{
headers: await createToastHeaders({
title: 'Connected',
description: `Your "${profile.username}" ${label} account has been connected.`,
}),
},
)
}
// // if the email matches a user in the db, then link the account and
// // make a new session
// const user = await prisma.user.findUnique({
// select: { id: true },
// where: { email: profile.email.toLowerCase() },
// })
// if (user) {
// await prisma.connection.create({
// data: {
// providerName,
// providerId: profile.id,
// userId: user.id,
// },
// })
// return makeSession(
// { request, userId: user.id },
// {
// headers: await createToastHeaders({
// title: 'Connected',
// description: `Your "${profile.username}" ${label} account has been connected.`,
// }),
// },
// )
// }

// this is a new user, so let's get them onboarded
const verifySession = await verifySessionStorage.getSession()
verifySession.set(onboardingEmailSessionKey, profile.email)
verifySession.set(prefilledProfileKey, {
...profile,
email: profile.email.toLowerCase(),
username: profile.username?.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase(),
})
verifySession.set(providerIdKey, profile.id)
const onboardingRedirect = [
`/onboarding/${providerName}`,
redirectTo ? new URLSearchParams({ redirectTo }) : null,
]
.filter(Boolean)
.join('?')
return redirect(onboardingRedirect, {
headers: combineHeaders(
{ 'set-cookie': await verifySessionStorage.commitSession(verifySession) },
destroyRedirectTo,
),
})
// // this is a new user, so let's get them onboarded
// const verifySession = await verifySessionStorage.getSession()
// verifySession.set(onboardingEmailSessionKey, profile.email)
// verifySession.set(prefilledProfileKey, {
// ...profile,
// email: profile.email.toLowerCase(),
// username: profile.username?.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase(),
// })
// verifySession.set(providerIdKey, profile.id)
// const onboardingRedirect = [
// `/onboarding/${providerName}`,
// redirectTo ? new URLSearchParams({ redirectTo }) : null,
// ]
// .filter(Boolean)
// .join('?')
// return redirect(onboardingRedirect, {
// headers: combineHeaders(
// { 'set-cookie': await verifySessionStorage.commitSession(verifySession) },
// destroyRedirectTo,
// ),
// })
}

async function makeSession(
{
request,
userId,
redirectTo,
}: { request: Request; userId: string; redirectTo?: string | null },
responseInit?: ResponseInit,
) {
redirectTo ??= '/'
const session = await prisma.session.create({
select: { id: true, expirationDate: true, userId: true },
data: {
expirationDate: getSessionExpirationDate(),
userId,
},
})
return handleNewSession(
{ request, session, redirectTo, remember: true },
{ headers: combineHeaders(responseInit?.headers, destroyRedirectTo) },
)
}
// async function makeSession(
// {
// request,
// userId,
// redirectTo,
// }: { request: Request; userId: string; redirectTo?: string | null },
// responseInit?: ResponseInit,
// ) {
// redirectTo ??= '/'
// const session = await prisma.session.create({
// select: { id: true, expirationDate: true, userId: true },
// data: {
// expirationDate: getSessionExpirationDate(),
// userId,
// },
// })
// return handleNewSession(
// { request, session, redirectTo, remember: true },
// { headers: combineHeaders(responseInit?.headers, destroyRedirectTo) },
// )
// }
Loading

0 comments on commit 05716dc

Please sign in to comment.