fix: hidden fields being mutated on patch (#2317)

This commit is contained in:
Jarrod Flesch
2023-03-14 15:35:58 -04:00
committed by GitHub
parent 5f1b0c21eb
commit 8d65ba1efd
4 changed files with 108 additions and 40 deletions

View File

@@ -140,7 +140,7 @@ async function update<TSlug extends keyof GeneratedTypes['collections']>(
entityConfig: collectionConfig, entityConfig: collectionConfig,
req, req,
overrideAccess: true, overrideAccess: true,
showHiddenFields, showHiddenFields: true,
}); });
// ///////////////////////////////////// // /////////////////////////////////////

View File

@@ -11,6 +11,7 @@ export const restrictedVersionsSlug = 'restricted-versions';
export const siblingDataSlug = 'sibling-data'; export const siblingDataSlug = 'sibling-data';
export const relyOnRequestHeadersSlug = 'rely-on-request-headers'; export const relyOnRequestHeadersSlug = 'rely-on-request-headers';
export const docLevelAccessSlug = 'doc-level-access'; export const docLevelAccessSlug = 'doc-level-access';
export const hiddenFieldsSlug = 'hidden-fields';
const openAccess = { const openAccess = {
create: () => true, 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) => { onInit: async (payload) => {
await payload.create({ await payload.create({

View File

@@ -1,10 +1,9 @@
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import payload from '../../src'; import payload from '../../src';
import type { Options as CreateOptions } from '../../src/collections/operations/local/create';
import { Forbidden } from '../../src/errors'; import { Forbidden } from '../../src/errors';
import type { PayloadRequest } from '../../src/types'; import type { PayloadRequest } from '../../src/types';
import { initPayloadTest } from '../helpers/configHelpers'; 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 type { Restricted, Post, RelyOnRequestHeader } from './payload-types';
import { firstArrayText, secondArrayText } from './shared'; import { firstArrayText, secondArrayText } from './shared';
@@ -34,7 +33,38 @@ describe('Access Control', () => {
await payload.mongoMemoryServer.stop(); 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 () => { it('should be able to restrict access based upon siblingData', async () => {
const { id } = await payload.create({ const { id } = await payload.create({
@@ -220,7 +250,7 @@ describe('Access Control', () => {
}); });
}); });
async function createDoc<Collection>(data: Partial<Collection>, overrideSlug = slug, options?: Partial<CreateOptions<Collection>>): Promise<Collection> { async function createDoc<Collection>(data: Partial<Collection>, overrideSlug = slug, options?: Partial<Collection>): Promise<Collection> {
return payload.create({ return payload.create({
...options, ...options,
collection: overrideSlug, collection: overrideSlug,

View File

@@ -5,11 +5,20 @@
* and re-run `payload generate:types` to regenerate this file. * and re-run `payload generate:types` to regenerate this file.
*/ */
export interface Config {} export interface Config {
/** collections: {
* This interface was referenced by `Config`'s JSON-Schema users: User;
* via the `definition` "users". 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 { export interface User {
id: string; id: string;
email?: string; email?: string;
@@ -19,15 +28,12 @@ export interface User {
lockUntil?: string; lockUntil?: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
password?: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "posts".
*/
export interface Post { export interface Post {
id: string; id: string;
restrictedField?: string; restrictedField?: string;
group: { group?: {
restrictedGroupText?: string; restrictedGroupText?: string;
}; };
restrictedRowText?: string; restrictedRowText?: string;
@@ -35,43 +41,27 @@ export interface Post {
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "restricted".
*/
export interface Restricted { export interface Restricted {
id: string; id: string;
name?: string; name?: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "read-only-collection".
*/
export interface ReadOnlyCollection { export interface ReadOnlyCollection {
id: string; id: string;
name?: string; name?: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "restricted-versions".
*/
export interface RestrictedVersion { export interface RestrictedVersion {
id: string; id: string;
name?: string; name?: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "sibling-data".
*/
export interface SiblingDatum { export interface SiblingDatum {
id: string; id: string;
array: { array?: {
allowPublicReadability?: boolean; allowPublicReadability?: boolean;
text?: string; text?: string;
id?: string; id?: string;
@@ -79,20 +69,12 @@ export interface SiblingDatum {
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "rely-on-request-headers".
*/
export interface RelyOnRequestHeader { export interface RelyOnRequestHeader {
id: string; id: string;
name?: string; name?: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "doc-level-access".
*/
export interface DocLevelAccess { export interface DocLevelAccess {
id: string; id: string;
approvedForRemoval?: boolean; approvedForRemoval?: boolean;
@@ -101,3 +83,18 @@ export interface DocLevelAccess {
createdAt: string; createdAt: string;
updatedAt: 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;
}