From 8d65ba1efd8744042bbaf669c10b6837a6b972f8 Mon Sep 17 00:00:00 2001 From: Jarrod Flesch <30633324+JarrodMFlesch@users.noreply.github.com> Date: Tue, 14 Mar 2023 15:35:58 -0400 Subject: [PATCH] fix: hidden fields being mutated on patch (#2317) --- src/collections/operations/update.ts | 2 +- test/access-control/config.ts | 41 +++++++++++++++++ test/access-control/int.spec.ts | 38 ++++++++++++++-- test/access-control/payload-types.ts | 67 +++++++++++++--------------- 4 files changed, 108 insertions(+), 40 deletions(-) diff --git a/src/collections/operations/update.ts b/src/collections/operations/update.ts index fd6da5dd52..e761887378 100644 --- a/src/collections/operations/update.ts +++ b/src/collections/operations/update.ts @@ -140,7 +140,7 @@ async function update( entityConfig: collectionConfig, req, overrideAccess: true, - showHiddenFields, + showHiddenFields: true, }); // ///////////////////////////////////// diff --git a/test/access-control/config.ts b/test/access-control/config.ts index 9ada7ce107..31e9ca53e9 100644 --- a/test/access-control/config.ts +++ b/test/access-control/config.ts @@ -11,6 +11,7 @@ export const restrictedVersionsSlug = 'restricted-versions'; export const siblingDataSlug = 'sibling-data'; export const relyOnRequestHeadersSlug = 'rely-on-request-headers'; export const docLevelAccessSlug = 'doc-level-access'; +export const hiddenFieldsSlug = 'hidden-fields'; const openAccess = { create: () => true, @@ -242,6 +243,46 @@ export default buildConfig({ }, ], }, + { + slug: hiddenFieldsSlug, + access: openAccess, + fields: [ + { + name: 'title', + type: 'text', + }, + { + name: 'partiallyHiddenGroup', + type: 'group', + fields: [ + { + name: 'name', + type: 'text', + }, + { + name: 'value', + type: 'text', + hidden: true, + }, + ], + }, + { + name: 'partiallyHiddenArray', + type: 'array', + fields: [ + { + name: 'name', + type: 'text', + }, + { + name: 'value', + type: 'text', + hidden: true, + }, + ], + }, + ], + }, ], onInit: async (payload) => { await payload.create({ diff --git a/test/access-control/int.spec.ts b/test/access-control/int.spec.ts index fd337dfa86..6599acace7 100644 --- a/test/access-control/int.spec.ts +++ b/test/access-control/int.spec.ts @@ -1,10 +1,9 @@ import mongoose from 'mongoose'; import payload from '../../src'; -import type { Options as CreateOptions } from '../../src/collections/operations/local/create'; import { Forbidden } from '../../src/errors'; import type { PayloadRequest } from '../../src/types'; import { initPayloadTest } from '../helpers/configHelpers'; -import { relyOnRequestHeadersSlug, requestHeaders, restrictedSlug, siblingDataSlug, slug } from './config'; +import { hiddenFieldsSlug, relyOnRequestHeadersSlug, requestHeaders, restrictedSlug, siblingDataSlug, slug } from './config'; import type { Restricted, Post, RelyOnRequestHeader } from './payload-types'; import { firstArrayText, secondArrayText } from './shared'; @@ -34,7 +33,38 @@ describe('Access Control', () => { await payload.mongoMemoryServer.stop(); }); - it.todo('should properly prevent / allow public users from reading a restricted field'); + it('should not affect hidden fields when patching data', async () => { + const doc = await payload.create({ + collection: hiddenFieldsSlug, + data: { + partiallyHiddenArray: [{ + name: 'public_name', + value: 'private_value', + }], + partiallyHiddenGroup: { + name: 'public_name', + value: 'private_value', + }, + }, + }); + + await payload.update({ + collection: hiddenFieldsSlug, + id: doc.id, + data: { + title: 'Doc Title', + }, + }); + + const updatedDoc = await payload.findByID({ + collection: hiddenFieldsSlug, + id: doc.id, + showHiddenFields: true, + }); + + expect(updatedDoc.partiallyHiddenGroup.value).toEqual('private_value'); + expect(updatedDoc.partiallyHiddenArray[0].value).toEqual('private_value'); + }); it('should be able to restrict access based upon siblingData', async () => { const { id } = await payload.create({ @@ -220,7 +250,7 @@ describe('Access Control', () => { }); }); -async function createDoc(data: Partial, overrideSlug = slug, options?: Partial>): Promise { +async function createDoc(data: Partial, overrideSlug = slug, options?: Partial): Promise { return payload.create({ ...options, collection: overrideSlug, diff --git a/test/access-control/payload-types.ts b/test/access-control/payload-types.ts index 5cc6bf23db..b4df1d4b89 100644 --- a/test/access-control/payload-types.ts +++ b/test/access-control/payload-types.ts @@ -5,11 +5,20 @@ * and re-run `payload generate:types` to regenerate this file. */ -export interface Config {} -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "users". - */ +export interface Config { + collections: { + users: User; + posts: Post; + restricted: Restricted; + 'read-only-collection': ReadOnlyCollection; + 'restricted-versions': RestrictedVersion; + 'sibling-data': SiblingDatum; + 'rely-on-request-headers': RelyOnRequestHeader; + 'doc-level-access': DocLevelAccess; + 'hidden-fields': HiddenField; + }; + globals: {}; +} export interface User { id: string; email?: string; @@ -19,15 +28,12 @@ export interface User { lockUntil?: string; createdAt: string; updatedAt: string; + password?: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "posts". - */ export interface Post { id: string; restrictedField?: string; - group: { + group?: { restrictedGroupText?: string; }; restrictedRowText?: string; @@ -35,43 +41,27 @@ export interface Post { createdAt: string; updatedAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "restricted". - */ export interface Restricted { id: string; name?: string; createdAt: string; updatedAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "read-only-collection". - */ export interface ReadOnlyCollection { id: string; name?: string; createdAt: string; updatedAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "restricted-versions". - */ export interface RestrictedVersion { id: string; name?: string; createdAt: string; updatedAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "sibling-data". - */ export interface SiblingDatum { id: string; - array: { + array?: { allowPublicReadability?: boolean; text?: string; id?: string; @@ -79,20 +69,12 @@ export interface SiblingDatum { createdAt: string; updatedAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "rely-on-request-headers". - */ export interface RelyOnRequestHeader { id: string; name?: string; createdAt: string; updatedAt: string; } -/** - * This interface was referenced by `Config`'s JSON-Schema - * via the `definition` "doc-level-access". - */ export interface DocLevelAccess { id: string; approvedForRemoval?: boolean; @@ -101,3 +83,18 @@ export interface DocLevelAccess { createdAt: string; updatedAt: string; } +export interface HiddenField { + id: string; + title?: string; + partiallyHiddenGroup?: { + name?: string; + value?: string; + }; + partiallyHiddenArray?: { + name?: string; + value?: string; + id?: string; + }[]; + createdAt: string; + updatedAt: string; +}