Skip to content

Commit

Permalink
Merge pull request #1520 from bcgov/feat/1437-1
Browse files Browse the repository at this point in the history
feat: add write base filter in security layer
  • Loading branch information
junminahn authored Dec 6, 2023
2 parents e335804 + 6b9a120 commit 26caf0c
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 19 deletions.
14 changes: 8 additions & 6 deletions core/modelService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { Prisma, PrismaClient, $Enums } from '@prisma/client';
import { Session } from 'next-auth';

export abstract class ModelService<TFilter> {
abstract secureFilter(): Promise<TFilter>;
abstract readFilter(): Promise<TFilter>;
abstract writeFilter(): Promise<TFilter>;
abstract decorate(doc: any): Promise<any>;

protected client!: PrismaClient;
Expand All @@ -14,16 +15,17 @@ export abstract class ModelService<TFilter> {
this.session = session;
}

async genFilter(where: TFilter) {
async genFilter(where: TFilter, mode: 'read' | 'write') {
let filter = where;

const secureFilter = await this.secureFilter();
const baseFilterFn = mode === 'read' ? this.readFilter : this.writeFilter;
const baseFilter = await baseFilterFn();

if (secureFilter) {
if (baseFilter) {
if (where) {
filter = { AND: [secureFilter, where] } as TFilter;
filter = { AND: [baseFilter, where] } as TFilter;
} else {
filter = secureFilter;
filter = baseFilter;
}
}

Expand Down
14 changes: 13 additions & 1 deletion core/services/privateCloudProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class PrivateCloudProjectService extends ModelService<Prisma.PrivateCloudProjectWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.PrivateCloudProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
Expand All @@ -20,6 +20,18 @@ export class PrivateCloudProjectService extends ModelService<Prisma.PrivateCloud
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.PrivateCloudProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

async decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
14 changes: 13 additions & 1 deletion core/services/privateCloudRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class PrivateCloudRequestService extends ModelService<Prisma.PrivateCloudRequestWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.PrivateCloudRequestWhereInput;
if (!this.session.isAdmin) {
const res = await this.client.privateCloudRequestedProject.findMany({
Expand All @@ -20,6 +20,18 @@ export class PrivateCloudRequestService extends ModelService<Prisma.PrivateCloud
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.PrivateCloudRequestWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

async decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
14 changes: 13 additions & 1 deletion core/services/privateCloudRequestedProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class PrivateCloudRequestedProjectService extends ModelService<Prisma.PrivateCloudRequestedProjectWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.PrivateCloudRequestedProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
Expand All @@ -20,6 +20,18 @@ export class PrivateCloudRequestedProjectService extends ModelService<Prisma.Pri
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.PrivateCloudRequestedProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

async decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
14 changes: 13 additions & 1 deletion core/services/publicCloudProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class PublicCloudProjectService extends ModelService<Prisma.PublicCloudProjectWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.PublicCloudProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
Expand All @@ -20,6 +20,18 @@ export class PublicCloudProjectService extends ModelService<Prisma.PublicCloudPr
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.PublicCloudProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

async decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
14 changes: 13 additions & 1 deletion core/services/publicCloudRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class PublicCloudRequestService extends ModelService<Prisma.PublicCloudRequestWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.PublicCloudRequestWhereInput;
if (!this.session.isAdmin) {
const res = await this.client.publicCloudRequestedProject.findMany({
Expand All @@ -21,6 +21,18 @@ export class PublicCloudRequestService extends ModelService<Prisma.PublicCloudRe
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.PublicCloudRequestWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

async decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
14 changes: 13 additions & 1 deletion core/services/publicCloudRequestedProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class PublicCloudRequestedProjectService extends ModelService<Prisma.PublicCloudRequestedProjectWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.PublicCloudRequestedProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
Expand All @@ -20,6 +20,18 @@ export class PublicCloudRequestedProjectService extends ModelService<Prisma.Publ
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.PublicCloudRequestedProjectWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
14 changes: 13 additions & 1 deletion core/services/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Session } from 'next-auth';
import { ModelService } from '../modelService';

export class UserService extends ModelService<Prisma.UserWhereInput> {
async secureFilter() {
async readFilter() {
let baseFilter!: Prisma.UserWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
Expand All @@ -18,6 +18,18 @@ export class UserService extends ModelService<Prisma.UserWhereInput> {
return baseFilter;
}

async writeFilter() {
let baseFilter!: Prisma.UserWhereInput;
if (!this.session.isAdmin) {
baseFilter = {
// Adding a dummy query to ensure no documents match
created: new Date(),
};
}

return baseFilter;
}

async decorate(doc: any) {
doc._permissions = {
view: true,
Expand Down
25 changes: 19 additions & 6 deletions lib/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,37 @@ const prisma =
async $allOperations({ model, operation, args, query }) {
if (
!model ||
!['findUnique', 'findUniqueOrThrow', 'findFirst', 'findFirstOrThrow', 'findMany'].includes(operation)
![
'findUnique',
'findUniqueOrThrow',
'findFirst',
'findFirstOrThrow',
'findMany',
'update',
'upsert',
'updateMany',
].includes(operation)
) {
return query(args);
}

const { session, ...validArgs } = args;
if (session === undefined) return query(validArgs);

const multi = ['findMany'].includes(operation);
if (!session?.userId) return multi ? [] : null;

const svc = getService(model, prisma, session);
if (!svc) return query(args);
if (!svc) return query(validArgs);

const multi = ['findMany'].includes(operation);
const writeOp = ['update', 'upsert', 'updateMany'].includes(operation);

const { where, ...otherArgs } = validArgs;
const filter = await svc.genFilter(where);
const filter = await svc.genFilter(where, writeOp ? 'write' : 'read');
const result = await query({ ...otherArgs, where: filter });

if (operation === 'updateMany') {
return result;
}

const decorated = multi ? await Promise.all(result.map(svc.decorate)) : await svc.decorate(result);
return decorated;
},
Expand Down

0 comments on commit 26caf0c

Please sign in to comment.