Skip to content
This repository was archived by the owner on Apr 23, 2025. It is now read-only.

Commit 4bc72a8

Browse files
authored
fix: issue 599, throw error if the given user context doesn't contain full id fields (zenstackhq#629)
1 parent 2ef93cb commit 4bc72a8

File tree

4 files changed

+25
-8
lines changed

4 files changed

+25
-8
lines changed

packages/runtime/src/enhancements/policy/index.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import path from 'path';
55
import semver from 'semver';
66
import { PRISMA_MINIMUM_VERSION } from '../../constants';
77
import { AuthUser, DbClientContract } from '../../types';
8+
import { hasAllFields } from '../../validation';
89
import { getDefaultModelMeta } from '../model-meta';
910
import { makeProxy } from '../proxy';
1011
import type { ModelMeta, PolicyDef, ZodSchemas } from '../types';
12+
import { getIdFields } from '../utils';
1113
import { PolicyProxyHandler } from './handler';
1214

1315
/**
@@ -70,6 +72,21 @@ export function withPolicy<DbClient extends object>(
7072
const _modelMeta = options?.modelMeta ?? getDefaultModelMeta();
7173
const _zodSchemas = options?.zodSchemas ?? getDefaultZodSchemas();
7274

75+
// validate user context
76+
if (context?.user) {
77+
const idFields = getIdFields(_modelMeta, 'User');
78+
if (
79+
!hasAllFields(
80+
context.user,
81+
idFields.map((f) => f.name)
82+
)
83+
) {
84+
throw new Error(
85+
`Invalid user context: must have valid ID field ${idFields.map((f) => `"${f.name}"`).join(', ')}`
86+
);
87+
}
88+
}
89+
7390
return makeProxy(
7491
prisma,
7592
_modelMeta,

packages/runtime/src/enhancements/utils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ export function getModelFields(data: object) {
1818
* Gets id fields for the given model.
1919
*/
2020
export function getIdFields(modelMeta: ModelMeta, model: string, throwIfNotFound = false) {
21-
const fields = modelMeta.fields[lowerCaseFirst(model)];
21+
let fields = modelMeta.fields[lowerCaseFirst(model)];
2222
if (!fields) {
23-
throw new Error(`Unable to load fields for ${model}`);
23+
if (throwIfNotFound) {
24+
throw new Error(`Unable to load fields for ${model}`);
25+
} else {
26+
fields = {};
27+
}
2428
}
2529
const result = Object.values(fields).filter((f) => f.isId);
2630
if (result.length === 0 && throwIfNotFound) {

tests/integration/tests/enhancements/with-policy/auth.test.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,7 @@ describe('With Policy: auth() test', () => {
113113
const authDb = withPolicy();
114114
await expect(authDb.post.update({ where: { id: '1' }, data: { title: 'bcd' } })).toBeRejectedByPolicy();
115115

116-
const authDb1 = withPolicy({ id: null });
117-
await expect(authDb1.post.update({ where: { id: '1' }, data: { title: 'bcd' } })).rejects.toThrow();
116+
expect(() => withPolicy({ id: null })).toThrow(/Invalid user context/);
118117

119118
const authDb2 = withPolicy({ id: 'user1' });
120119
await expect(authDb2.post.update({ where: { id: '1' }, data: { title: 'bcd' } })).toResolveTruthy();
@@ -148,9 +147,6 @@ describe('With Policy: auth() test', () => {
148147

149148
await expect(db.post.update({ where: { id: '1' }, data: { title: 'bcd' } })).toBeRejectedByPolicy();
150149

151-
const authDb1 = withPolicy({ id: null });
152-
await expect(authDb1.post.update({ where: { id: '1' }, data: { title: 'bcd' } })).rejects.toThrow();
153-
154150
const authDb2 = withPolicy({ id: 'user1' });
155151
await expect(authDb2.post.update({ where: { id: '1' }, data: { title: 'bcd' } })).toResolveTruthy();
156152
});

tests/integration/tests/enhancements/with-policy/multi-id-fields.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ describe('With Policy: multiple id fields', () => {
124124
await prisma.user.create({ data: { x: '1', y: '1' } });
125125
await prisma.user.create({ data: { x: '1', y: '2' } });
126126

127-
const anonDb = withPolicy({});
127+
const anonDb = withPolicy();
128128

129129
await expect(
130130
anonDb.m.create({ data: { owner: { connect: { x_y: { x: '1', y: '2' } } } } })

0 commit comments

Comments
 (0)