Kaynağa Gözat

fix(core): Prevent exposure of private custom fields via JSON type

Fixes #3049

(cherry picked from commit 042abdb9ece99845a48fed94890c8973bb68722c)
Michael Bromley 1 yıl önce
ebeveyn
işleme
29b83d9596

+ 26 - 10
packages/core/e2e/custom-fields.e2e-spec.ts

@@ -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,
 });
@@ -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', () => {
@@ -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');
         });

+ 11 - 0
packages/core/src/api/config/generate-resolvers.ts

@@ -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 };
 }