Skip to content

Commit

Permalink
fix(core): Prevent exposure of private custom fields via JSON type
Browse files Browse the repository at this point in the history
Fixes #3049
  • Loading branch information
michaelbromley committed Sep 9, 2024
1 parent 7ae064c commit 042abdb
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 10 deletions.
36 changes: 26 additions & 10 deletions packages/core/e2e/custom-fields.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ const customConfig = mergeConfig(testConfig(), {
readonly: true,
},
],
Collection: [
{ name: 'secretKey1', type: 'string', defaultValue: '', public: false, internal: true },
{ name: 'secretKey2', type: 'string', defaultValue: '', public: false, internal: false },
],
OrderLine: [{ name: 'validateInt', type: 'int', min: 0, max: 10 }],
} as CustomFields,
});
Expand Down Expand Up @@ -942,6 +946,20 @@ describe('Custom fields', () => {
`);
}, 'Cannot query field "internalString" on type "ProductCustomFields"'),
);

// https://github.com/vendure-ecommerce/vendure/issues/3049
it('does not leak private fields via JSON type', async () => {
const { collection } = await shopClient.query(gql`
query {
collection(id: "T_1") {
id
customFields
}
}
`);

expect(collection.customFields).toBe(null);
});
});

describe('sort & filter', () => {
Expand Down Expand Up @@ -1087,18 +1105,16 @@ describe('Custom fields', () => {

describe('unique constraint', () => {
it('setting unique value works', async () => {
const result = await adminClient.query(
gql`
mutation {
updateProduct(input: { id: "T_1", customFields: { uniqueString: "foo" } }) {
id
customFields {
uniqueString
}
const result = await adminClient.query(gql`
mutation {
updateProduct(input: { id: "T_1", customFields: { uniqueString: "foo" } }) {
id
customFields {
uniqueString
}
}
`,
);
}
`);

expect(result.updateProduct.customFields.uniqueString).toBe('foo');
});
Expand Down
11 changes: 11 additions & 0 deletions packages/core/src/api/config/generate-resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,17 @@ function generateCustomFieldRelationResolvers(
} as any;
}
}
const allCustomFieldsAreNonPublic = customFields.every(
f => f.public === false || f.internal === true,
);
if (allCustomFieldsAreNonPublic) {
// When an entity has only non-public custom fields, the GraphQL type used for the
// customFields field is `JSON`. This type will simply return the full object, which
// will cause a leak of private data unless we force a `null` return value in the case
// that there are no public fields.
// See https://github.com/vendure-ecommerce/vendure/issues/3049
shopResolvers[entityName] = { customFields: () => null };
}
}
return { adminResolvers, shopResolvers };
}
Expand Down

0 comments on commit 042abdb

Please sign in to comment.