Skip to content

Commit 874279c

Browse files
authored
fix(next): infinite loop when logging into root admin (#7412)
1 parent 7ed6634 commit 874279c

File tree

12 files changed

+82
-36
lines changed

12 files changed

+82
-36
lines changed

packages/next/src/utilities/initPage/handleAdminPage.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type {
77

88
import { notFound } from 'next/navigation.js'
99

10-
import { isAdminAuthRoute, isAdminRoute } from './shared.js'
10+
import { getRouteWithoutAdmin, isAdminAuthRoute, isAdminRoute } from './shared.js'
1111

1212
export const handleAdminPage = ({
1313
adminRoute,
@@ -20,9 +20,9 @@ export const handleAdminPage = ({
2020
permissions: Permissions
2121
route: string
2222
}) => {
23-
if (isAdminRoute(route, adminRoute)) {
24-
const baseAdminRoute = adminRoute && adminRoute !== '/' ? route.replace(adminRoute, '') : route
25-
const routeSegments = baseAdminRoute.split('/').filter(Boolean)
23+
if (isAdminRoute({ adminRoute, config, route })) {
24+
const routeWithoutAdmin = getRouteWithoutAdmin({ adminRoute, route })
25+
const routeSegments = routeWithoutAdmin.split('/').filter(Boolean)
2626
const [entityType, entitySlug, createOrID] = routeSegments
2727
const collectionSlug = entityType === 'collections' ? entitySlug : undefined
2828
const globalSlug = entityType === 'globals' ? entitySlug : undefined
@@ -47,7 +47,7 @@ export const handleAdminPage = ({
4747
}
4848
}
4949

50-
if (!permissions.canAccessAdmin && !isAdminAuthRoute(config, route, adminRoute)) {
50+
if (!permissions.canAccessAdmin && !isAdminAuthRoute({ adminRoute, config, route })) {
5151
notFound()
5252
}
5353

packages/next/src/utilities/initPage/handleAuthRedirect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const handleAuthRedirect = ({
2222
routes: { admin: adminRoute },
2323
} = config
2424

25-
if (!isAdminAuthRoute(config, route, adminRoute)) {
25+
if (!isAdminAuthRoute({ adminRoute, config, route })) {
2626
if (searchParams && 'redirect' in searchParams) delete searchParams.redirect
2727

2828
const redirectRoute = encodeURIComponent(
@@ -36,7 +36,7 @@ export const handleAuthRedirect = ({
3636
const customLoginRoute =
3737
typeof redirectUnauthenticatedUser === 'string' ? redirectUnauthenticatedUser : undefined
3838

39-
const loginRoute = isAdminRoute(route, adminRoute)
39+
const loginRoute = isAdminRoute({ adminRoute, config, route })
4040
? adminLoginRoute
4141
: customLoginRoute || loginRouteFromConfig
4242

packages/next/src/utilities/initPage/shared.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,42 @@ const authRouteKeys: (keyof SanitizedConfig['admin']['routes'])[] = [
1111
'reset',
1212
]
1313

14-
export const isAdminRoute = (route: string, adminRoute: string) => {
15-
return route.startsWith(adminRoute)
14+
export const isAdminRoute = ({
15+
adminRoute,
16+
config,
17+
route,
18+
}: {
19+
adminRoute: string
20+
config: SanitizedConfig
21+
route: string
22+
}): boolean => {
23+
return route.startsWith(adminRoute) && !isAdminAuthRoute({ adminRoute, config, route })
1624
}
1725

18-
export const isAdminAuthRoute = (config: SanitizedConfig, route: string, adminRoute: string) => {
26+
export const isAdminAuthRoute = ({
27+
adminRoute,
28+
config,
29+
route,
30+
}: {
31+
adminRoute: string
32+
config: SanitizedConfig
33+
route: string
34+
}): boolean => {
1935
const authRoutes = config.admin?.routes
2036
? Object.entries(config.admin.routes)
2137
.filter(([key]) => authRouteKeys.includes(key as keyof SanitizedConfig['admin']['routes']))
2238
.map(([_, value]) => value)
2339
: []
2440

25-
return authRoutes.some((r) => route.replace(adminRoute, '').startsWith(r))
41+
return authRoutes.some((r) => getRouteWithoutAdmin({ adminRoute, route }).startsWith(r))
42+
}
43+
44+
export const getRouteWithoutAdmin = ({
45+
adminRoute,
46+
route,
47+
}: {
48+
adminRoute: string
49+
route: string
50+
}): string => {
51+
return adminRoute && adminRoute !== '/' ? route.replace(adminRoute, '') : route
2652
}

test/access-control/e2e.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
closeNav,
1919
ensureCompilationIsDone,
2020
exactText,
21-
getAdminRoutes,
21+
getRoutes,
2222
initPageConsoleErrorCatch,
2323
login,
2424
openDocControls,
@@ -99,7 +99,7 @@ describe('access control', () => {
9999
routes: { logout: logoutRoute },
100100
},
101101
routes: { admin: adminRoute },
102-
} = getAdminRoutes({})
102+
} = getRoutes({})
103103

104104
logoutURL = `${serverURL}${adminRoute}${logoutRoute}`
105105
})

test/admin-root/app/favicon.ico

15 KB
Binary file not shown.

test/admin-root/config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ const dirname = path.dirname(filename)
1212

1313
export default buildConfigWithDefaults({
1414
collections: [PostsCollection],
15+
admin: {
16+
autoLogin: {
17+
email: devUser.email,
18+
password: devUser.password,
19+
prefillOnly: true,
20+
},
21+
},
1522
cors: ['http://localhost:3000', 'http://localhost:3001'],
1623
globals: [MenuGlobal],
1724
routes: {

test/admin-root/e2e.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import * as path from 'path'
55
import { adminRoute } from 'shared.js'
66
import { fileURLToPath } from 'url'
77

8-
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
8+
import { ensureCompilationIsDone, initPageConsoleErrorCatch, login } from '../helpers.js'
99
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
1010
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
1111
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
@@ -29,6 +29,8 @@ test.describe('Admin Panel (Root)', () => {
2929
page = await context.newPage()
3030
initPageConsoleErrorCatch(page)
3131

32+
await login({ page, serverURL, customRoutes: { admin: adminRoute } })
33+
3234
await ensureCompilationIsDone({
3335
customRoutes: {
3436
admin: adminRoute,

test/admin/e2e/1/e2e.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
checkPageTitle,
1111
ensureCompilationIsDone,
1212
exactText,
13-
getAdminRoutes,
13+
getRoutes,
1414
initPageConsoleErrorCatch,
1515
openDocControls,
1616
openNav,
@@ -76,7 +76,7 @@ describe('admin1', () => {
7676
let customFieldsURL: AdminUrlUtil
7777
let disableDuplicateURL: AdminUrlUtil
7878
let serverURL: string
79-
let adminRoutes: ReturnType<typeof getAdminRoutes>
79+
let adminRoutes: ReturnType<typeof getRoutes>
8080
let loginURL: string
8181

8282
beforeAll(async ({ browser }, testInfo) => {
@@ -106,7 +106,7 @@ describe('admin1', () => {
106106

107107
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
108108

109-
adminRoutes = getAdminRoutes({ customAdminRoutes })
109+
adminRoutes = getRoutes({ customAdminRoutes })
110110

111111
loginURL = `${serverURL}${adminRoutes.routes.admin}${adminRoutes.admin.routes.login}`
112112
})

test/admin/e2e/2/e2e.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { Config, Geo, Post } from '../../payload-types.js'
1010
import {
1111
ensureCompilationIsDone,
1212
exactText,
13-
getAdminRoutes,
13+
getRoutes,
1414
initPageConsoleErrorCatch,
1515
openDocDrawer,
1616
openNav,
@@ -44,7 +44,7 @@ describe('admin2', () => {
4444
let postsUrl: AdminUrlUtil
4545

4646
let serverURL: string
47-
let adminRoutes: ReturnType<typeof getAdminRoutes>
47+
let adminRoutes: ReturnType<typeof getRoutes>
4848

4949
beforeAll(async ({ browser }, testInfo) => {
5050
const prebuild = Boolean(process.env.CI)
@@ -69,7 +69,7 @@ describe('admin2', () => {
6969

7070
await ensureCompilationIsDone({ customAdminRoutes, page, serverURL })
7171

72-
adminRoutes = getAdminRoutes({ customAdminRoutes })
72+
adminRoutes = getRoutes({ customAdminRoutes })
7373
})
7474
beforeEach(async () => {
7575
await reInitializeDB({

test/auth/e2e.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type { Config } from './payload-types.js'
1313

1414
import {
1515
ensureCompilationIsDone,
16-
getAdminRoutes,
16+
getRoutes,
1717
initPageConsoleErrorCatch,
1818
saveDocAndAssert,
1919
} from '../helpers.js'
@@ -49,7 +49,7 @@ const createFirstUser = async ({
4949
routes: { createFirstUser: createFirstUserRoute },
5050
},
5151
routes: { admin: adminRoute },
52-
} = getAdminRoutes({
52+
} = getRoutes({
5353
customAdminRoutes,
5454
customRoutes,
5555
})

0 commit comments

Comments
 (0)