fix: upload and auth endpoints are mounted for all collections (#11231)
This PR ensures, that collections that don't have `auth: true` don't mount authentication related endpoints like `/me`, the same for uploads. Additionally, moves upload-related endpoints to `uploads/endpoints/*`.
This commit is contained in:
@@ -3,11 +3,13 @@ import type { LoginWithUsernameOptions } from '../../auth/types.js'
|
|||||||
import type { Config, SanitizedConfig } from '../../config/types.js'
|
import type { Config, SanitizedConfig } from '../../config/types.js'
|
||||||
import type { CollectionConfig, SanitizedCollectionConfig, SanitizedJoins } from './types.js'
|
import type { CollectionConfig, SanitizedCollectionConfig, SanitizedJoins } from './types.js'
|
||||||
|
|
||||||
|
import { authCollectionEndpoints } from '../../auth/endpoints/index.js'
|
||||||
import { getBaseAuthFields } from '../../auth/getAuthFields.js'
|
import { getBaseAuthFields } from '../../auth/getAuthFields.js'
|
||||||
import { TimestampsRequired } from '../../errors/TimestampsRequired.js'
|
import { TimestampsRequired } from '../../errors/TimestampsRequired.js'
|
||||||
import { sanitizeFields } from '../../fields/config/sanitize.js'
|
import { sanitizeFields } from '../../fields/config/sanitize.js'
|
||||||
import { fieldAffectsData } from '../../fields/config/types.js'
|
import { fieldAffectsData } from '../../fields/config/types.js'
|
||||||
import mergeBaseFields from '../../fields/mergeBaseFields.js'
|
import mergeBaseFields from '../../fields/mergeBaseFields.js'
|
||||||
|
import { uploadCollectionEndpoints } from '../../uploads/endpoints/index.js'
|
||||||
import { getBaseUploadFields } from '../../uploads/getBaseFields.js'
|
import { getBaseUploadFields } from '../../uploads/getBaseFields.js'
|
||||||
import { deepMergeWithReactComponents } from '../../utilities/deepMerge.js'
|
import { deepMergeWithReactComponents } from '../../utilities/deepMerge.js'
|
||||||
import { flattenAllFields } from '../../utilities/flattenAllFields.js'
|
import { flattenAllFields } from '../../utilities/flattenAllFields.js'
|
||||||
@@ -58,6 +60,18 @@ export const sanitizeCollection = async (
|
|||||||
sanitized.endpoints = []
|
sanitized.endpoints = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sanitized.auth) {
|
||||||
|
for (const endpoint of authCollectionEndpoints) {
|
||||||
|
sanitized.endpoints.push(endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sanitized.upload) {
|
||||||
|
for (const endpoint of uploadCollectionEndpoints) {
|
||||||
|
sanitized.endpoints.push(endpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const endpoint of defaultCollectionEndpoints) {
|
for (const endpoint of defaultCollectionEndpoints) {
|
||||||
sanitized.endpoints.push(endpoint)
|
sanitized.endpoints.push(endpoint)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { Endpoint } from '../../config/types.js'
|
import type { Endpoint } from '../../config/types.js'
|
||||||
|
|
||||||
import { authCollectionEndpoints } from '../../auth/endpoints/index.js'
|
|
||||||
import { wrapInternalEndpoints } from '../../utilities/wrapInternalEndpoints.js'
|
import { wrapInternalEndpoints } from '../../utilities/wrapInternalEndpoints.js'
|
||||||
import { countHandler } from './count.js'
|
import { countHandler } from './count.js'
|
||||||
import { createHandler } from './create.js'
|
import { createHandler } from './create.js'
|
||||||
@@ -12,15 +11,12 @@ import { findHandler } from './find.js'
|
|||||||
import { findByIDHandler } from './findByID.js'
|
import { findByIDHandler } from './findByID.js'
|
||||||
import { findVersionByIDHandler } from './findVersionByID.js'
|
import { findVersionByIDHandler } from './findVersionByID.js'
|
||||||
import { findVersionsHandler } from './findVersions.js'
|
import { findVersionsHandler } from './findVersions.js'
|
||||||
import { getFileHandler } from './getFile.js'
|
|
||||||
import { getFileFromURLHandler } from './getFileFromURL.js'
|
|
||||||
import { previewHandler } from './preview.js'
|
import { previewHandler } from './preview.js'
|
||||||
import { restoreVersionHandler } from './restoreVersion.js'
|
import { restoreVersionHandler } from './restoreVersion.js'
|
||||||
import { updateHandler } from './update.js'
|
import { updateHandler } from './update.js'
|
||||||
import { updateByIDHandler } from './updateByID.js'
|
import { updateByIDHandler } from './updateByID.js'
|
||||||
|
|
||||||
export const defaultCollectionEndpoints: Endpoint[] = [
|
export const defaultCollectionEndpoints: Endpoint[] = [
|
||||||
...authCollectionEndpoints,
|
|
||||||
...wrapInternalEndpoints([
|
...wrapInternalEndpoints([
|
||||||
{
|
{
|
||||||
handler: countHandler,
|
handler: countHandler,
|
||||||
@@ -47,11 +43,6 @@ export const defaultCollectionEndpoints: Endpoint[] = [
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
path: '/access/:id?',
|
path: '/access/:id?',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
handler: getFileFromURLHandler,
|
|
||||||
method: 'get',
|
|
||||||
path: '/paste-url/:id?',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
handler: findVersionsHandler,
|
handler: findVersionsHandler,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
@@ -77,11 +68,6 @@ export const defaultCollectionEndpoints: Endpoint[] = [
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
path: '/versions/:id',
|
path: '/versions/:id',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
handler: getFileHandler,
|
|
||||||
method: 'get',
|
|
||||||
path: '/file/:filename',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
handler: previewHandler,
|
handler: previewHandler,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
|
|||||||
18
packages/payload/src/uploads/endpoints/index.ts
Normal file
18
packages/payload/src/uploads/endpoints/index.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import type { Endpoint } from '../../config/types.js'
|
||||||
|
|
||||||
|
import { wrapInternalEndpoints } from '../../utilities/wrapInternalEndpoints.js'
|
||||||
|
import { getFileHandler } from './getFile.js'
|
||||||
|
import { getFileFromURLHandler } from './getFileFromURL.js'
|
||||||
|
|
||||||
|
export const uploadCollectionEndpoints: Endpoint[] = wrapInternalEndpoints([
|
||||||
|
{
|
||||||
|
handler: getFileFromURLHandler,
|
||||||
|
method: 'get',
|
||||||
|
path: '/paste-url/:id?',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
handler: getFileHandler,
|
||||||
|
method: 'get',
|
||||||
|
path: '/file/:filename',
|
||||||
|
},
|
||||||
|
])
|
||||||
@@ -17,8 +17,8 @@ import {
|
|||||||
errorOnHookSlug,
|
errorOnHookSlug,
|
||||||
methods,
|
methods,
|
||||||
pointSlug,
|
pointSlug,
|
||||||
relationSlug,
|
|
||||||
postsSlug,
|
postsSlug,
|
||||||
|
relationSlug,
|
||||||
} from './config.js'
|
} from './config.js'
|
||||||
|
|
||||||
const filename = fileURLToPath(import.meta.url)
|
const filename = fileURLToPath(import.meta.url)
|
||||||
@@ -1454,7 +1454,7 @@ describe('collections-rest', () => {
|
|||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
await createPost({
|
await createPost({
|
||||||
number: i,
|
number: i,
|
||||||
relationField: relatedDoc.id as string,
|
relationField: relatedDoc.id,
|
||||||
title: 'paginate-test',
|
title: 'paginate-test',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1733,6 +1733,73 @@ describe('collections-rest', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not mount auth endpoints for collection without auth', async () => {
|
||||||
|
const authEndpoints = [
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/forgot-password',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/login',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/logout',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/refresh-token',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/first-register',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/reset-password',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'post',
|
||||||
|
path: '/unlock',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const endpoint of authEndpoints) {
|
||||||
|
const result = await restClient[endpoint.method.toUpperCase()](
|
||||||
|
`/${endpointsSlug}${endpoint.path}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result.status).toBe(404)
|
||||||
|
const json = await result.json()
|
||||||
|
|
||||||
|
expect(json.message.startsWith('Route not found')).toBeTruthy()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should not mount upload endpoints for collection without auth', async () => {
|
||||||
|
const uploadEndpoints = [
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
path: '/paste-url/some-id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: 'get',
|
||||||
|
path: '/file/some-filename.png',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const endpoint of uploadEndpoints) {
|
||||||
|
const result = await restClient[endpoint.method.toUpperCase()](
|
||||||
|
`/${endpointsSlug}${endpoint.path}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result.status).toBe(404)
|
||||||
|
|
||||||
|
expect((await result.json()).message.startsWith('Route not found')).toBeTruthy()
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
async function createPost(overrides?: Partial<Post>) {
|
async function createPost(overrides?: Partial<Post>) {
|
||||||
|
|||||||
Reference in New Issue
Block a user