Skip to content

Commit

Permalink
feat: restrict update/delete operator by bucket(-file) owner
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed Feb 27, 2024
1 parent d90c326 commit 07ec40a
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 31 deletions.
1 change: 1 addition & 0 deletions packages/server-storage/src/domains/bucket-file/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
*/

export * from './entity';
export * from './utils';
14 changes: 14 additions & 0 deletions packages/server-storage/src/domains/bucket-file/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import type { Actor } from '../actor';
import type { BucketFileEntity } from './entity';

export function isBucketFileOwnedByActor(entity: BucketFileEntity, actor: Actor) {
return entity.actor_type === actor.type &&
entity.actor_id === actor.id;
}
1 change: 1 addition & 0 deletions packages/server-storage/src/domains/bucket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
*/

export * from './entity';
export * from './utils';
14 changes: 14 additions & 0 deletions packages/server-storage/src/domains/bucket/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2024.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

import type { Actor } from '../actor';
import type { BucketEntity } from './entity';

export function isBucketOwnedByActor(entity: BucketEntity, actor: Actor) {
return entity.actor_type === actor.type &&
entity.actor_id === actor.id;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ import type { Request, Response } from 'routup';
import { sendAccepted, useRequestParam } from 'routup';
import { useDataSource } from 'typeorm-extension';
import { useMinio } from '../../../../core';
import { BucketFileEntity } from '../../../../domains';
import {
BucketFileEntity,
getActorFromRequest,
isBucketFileOwnedByActor,
isBucketOwnedByActor,
} from '../../../../domains';
import { useRequestEnv } from '../../../request';

export async function executeBucketFileRouteDeleteHandler(req: Request, res: Response) : Promise<any> {
const id = useRequestParam(req, 'id');

const ability = useRequestEnv(req, 'ability');
if (!ability.has(PermissionID.BUCKET_DROP)) {
throw new ForbiddenError();
}

const dataSource = await useDataSource();
const repository = dataSource.getRepository(BucketFileEntity);
const entity = await repository.findOne({
Expand All @@ -36,8 +36,19 @@ export async function executeBucketFileRouteDeleteHandler(req: Request, res: Res
throw new NotFoundError();
}

if (!isRealmResourceWritable(useRequestEnv(req, 'realm'), entity.realm_id)) {
throw new ForbiddenError();
const actor = getActorFromRequest(req);
if (
!isBucketOwnedByActor(entity.bucket, actor) &&
!isBucketFileOwnedByActor(entity, actor)
) {
const ability = useRequestEnv(req, 'ability');
if (!ability.has(PermissionID.BUCKET_EDIT)) {
throw new ForbiddenError();
}

if (!isRealmResourceWritable(useRequestEnv(req, 'realm'), entity.realm_id)) {
throw new ForbiddenError();
}
}

const minio = useMinio();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function executeBucketFileRouteGetOneHandler(req: Request, res: Res

const dataSource = await useDataSource();
const repository = dataSource.getRepository(BucketFileEntity);
const query = repository.createQueryBuilder('bucket')
const query = repository.createQueryBuilder('bucketFile')
.where('bucketFile.id = :id', { id });

applyQuery(query, useRequestQuery(req), {
Expand All @@ -29,6 +29,7 @@ export async function executeBucketFileRouteGetOneHandler(req: Request, res: Res
default: [
'id',
'name',
'path',
'directory',
'size',
'hash',
Expand All @@ -37,6 +38,7 @@ export async function executeBucketFileRouteGetOneHandler(req: Request, res: Res
'realm_id',
'actor_type',
'actor_id',
'bucket_id',
],
},
relations: {
Expand All @@ -57,14 +59,15 @@ export async function executeBucketFileRouteGetManyHandler(req: Request, res: Re
const dataSource = await useDataSource();

const repository = dataSource.getRepository(BucketFileEntity);
const query = repository.createQueryBuilder('bucket');
const query = repository.createQueryBuilder('bucketFile');

const { pagination } = applyQuery(query, useRequestQuery(req), {
defaultAlias: 'bucket',
defaultAlias: 'bucketFile',
fields: {
default: [
'id',
'name',
'path',
'directory',
'size',
'hash',
Expand All @@ -73,6 +76,7 @@ export async function executeBucketFileRouteGetManyHandler(req: Request, res: Re
'realm_id',
'actor_type',
'actor_id',
'bucket_id',
],
},
relations: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,29 @@ import type { Request, Response } from 'routup';
import { sendAccepted, useRequestParam } from 'routup';
import { useDataSource } from 'typeorm-extension';
import { useMinio } from '../../../../core';
import { BucketEntity } from '../../../../domains';
import { BucketEntity, getActorFromRequest, isBucketOwnedByActor } from '../../../../domains';
import { useRequestEnv } from '../../../request';

export async function executeBucketRouteDeleteHandler(req: Request, res: Response) : Promise<any> {
const id = useRequestParam(req, 'id');

const ability = useRequestEnv(req, 'ability');
if (!ability.has(PermissionID.BUCKET_DROP)) {
throw new ForbiddenError();
}

const dataSource = await useDataSource();
const repository = dataSource.getRepository(BucketEntity);
const entity = await repository.findOneBy({ id });

if (!entity) {
throw new NotFoundError();
}

if (!isRealmResourceWritable(useRequestEnv(req, 'realm'), entity.realm_id)) {
throw new ForbiddenError();
const actor = getActorFromRequest(req);
if (!isBucketOwnedByActor(entity, actor)) {
const ability = useRequestEnv(req, 'ability');
if (!ability.has(PermissionID.BUCKET_DROP)) {
throw new ForbiddenError();
}

if (!isRealmResourceWritable(useRequestEnv(req, 'realm'), entity.realm_id)) {
throw new ForbiddenError();
}
}

const { id: entityId, name: entityName } = entity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,35 @@ import type { Request, Response } from 'routup';
import { sendAccepted, useRequestParam } from 'routup';
import { useDataSource } from 'typeorm-extension';
import { useMinio } from '../../../../core';
import { BucketEntity } from '../../../../domains';
import { BucketEntity, getActorFromRequest, isBucketOwnedByActor } from '../../../../domains';
import { useRequestEnv } from '../../../request';
import { runBucketValidation } from '../utils/validation';

export async function executeBucketRouteUpdateHandler(req: Request, res: Response) : Promise<any> {
const id = useRequestParam(req, 'id');

const ability = useRequestEnv(req, 'ability');
if (!ability.has(PermissionID.BUCKET_EDIT)) {
throw new ForbiddenError();
}

const result = await runBucketValidation(req, 'update');
if (!result.data) {
return sendAccepted(res);
}

const id = useRequestParam(req, 'id');

const dataSource = await useDataSource();
const repository = dataSource.getRepository(BucketEntity);
let entity = await repository.findOneBy({ id });

if (!entity) {
throw new NotFoundError();
}

if (!isRealmResourceWritable(useRequestEnv(req, 'realm'), entity.realm_id)) {
throw new ForbiddenError();
const actor = getActorFromRequest(req);
if (!isBucketOwnedByActor(entity, actor)) {
const ability = useRequestEnv(req, 'ability');
if (!ability.has(PermissionID.BUCKET_EDIT)) {
throw new ForbiddenError();
}

if (!isRealmResourceWritable(useRequestEnv(req, 'realm'), entity.realm_id)) {
throw new ForbiddenError();
}
}

entity = repository.merge(entity, result.data);
Expand Down

0 comments on commit 07ec40a

Please sign in to comment.