Browse Source

refactoring of remaining controllers to use the HasPermission Decorator and HasPermissionGuard instead of explict checking

pull/2771/head
Fares Eidi 2 years ago
committed by Thomas Kaul
parent
commit
0f4d90dc40
  1. 15
      apps/api/src/app/access/access.controller.ts
  2. 9
      apps/api/src/app/account-balance/account-balance.controller.ts
  3. 40
      apps/api/src/app/account/account.controller.ts
  4. 195
      apps/api/src/app/admin/admin.controller.ts
  5. 44
      apps/api/src/app/admin/queue/queue.controller.ts
  6. 14
      apps/api/src/app/app.module.ts
  7. 18
      apps/api/src/app/auth-device/auth-device.controller.ts
  8. 29
      apps/api/src/app/benchmark/benchmark.controller.ts
  9. 22
      apps/api/src/app/cache/cache.controller.ts
  10. 6
      apps/api/src/app/import/import.controller.ts
  11. 23
      apps/api/src/app/order/order.controller.ts
  12. 31
      apps/api/src/app/platform/platform.controller.ts
  13. 25
      apps/api/src/app/tag/tag.controller.ts
  14. 19
      apps/api/src/app/user/user.controller.ts
  15. 10
      apps/api/src/guards/has-permission.guard.spec.ts
  16. 7
      apps/api/src/guards/has-permission.guard.ts

15
apps/api/src/app/access/access.controller.ts

@ -1,5 +1,5 @@
import { Access } from '@ghostfolio/common/interfaces'; import { Access } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Body, Body,
@ -19,6 +19,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { AccessService } from './access.service'; import { AccessService } from './access.service';
import { CreateAccessDto } from './create-access.dto'; import { CreateAccessDto } from './create-access.dto';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('access') @Controller('access')
export class AccessController { export class AccessController {
@ -59,18 +60,10 @@ export class AccessController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.createAccess)
public async createAccess( public async createAccess(
@Body() data: CreateAccessDto @Body() data: CreateAccessDto
): Promise<AccessModel> { ): Promise<AccessModel> {
if (
!hasPermission(this.request.user.permissions, permissions.createAccess)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.accessService.createAccess({ return this.accessService.createAccess({
alias: data.alias || undefined, alias: data.alias || undefined,
GranteeUser: data.granteeUserId GranteeUser: data.granteeUserId
@ -82,11 +75,11 @@ export class AccessController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteAccess)
public async deleteAccess(@Param('id') id: string): Promise<AccessModel> { public async deleteAccess(@Param('id') id: string): Promise<AccessModel> {
const access = await this.accessService.access({ id }); const access = await this.accessService.access({ id });
if ( if (
!hasPermission(this.request.user.permissions, permissions.deleteAccess) ||
!access || !access ||
access.userId !== this.request.user.id access.userId !== this.request.user.id
) { ) {

9
apps/api/src/app/account-balance/account-balance.controller.ts

@ -10,8 +10,10 @@ import {
} from '@nestjs/common'; } from '@nestjs/common';
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { AccountBalance } from '@prisma/client'; import { permissions } from '@ghostfolio/common/permissions';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { AccountBalance } from '@prisma/client';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { AccountBalanceService } from './account-balance.service'; import { AccountBalanceService } from './account-balance.service';
@ -24,6 +26,7 @@ export class AccountBalanceController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteAccountBalance)
public async deleteAccountBalance( public async deleteAccountBalance(
@Param('id') id: string @Param('id') id: string
): Promise<AccountBalance> { ): Promise<AccountBalance> {
@ -32,10 +35,6 @@ export class AccountBalanceController {
}); });
if ( if (
!hasPermission(
this.request.user.permissions,
permissions.deleteAccountBalance
) ||
!accountBalance || !accountBalance ||
accountBalance.userId !== this.request.user.id accountBalance.userId !== this.request.user.id
) { ) {

40
apps/api/src/app/account/account.controller.ts

@ -7,7 +7,7 @@ import {
AccountBalancesResponse, AccountBalancesResponse,
Accounts Accounts
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
import type { import type {
AccountWithValue, AccountWithValue,
RequestWithUser RequestWithUser
@ -35,6 +35,7 @@ import { AccountService } from './account.service';
import { CreateAccountDto } from './create-account.dto'; import { CreateAccountDto } from './create-account.dto';
import { TransferBalanceDto } from './transfer-balance.dto'; import { TransferBalanceDto } from './transfer-balance.dto';
import { UpdateAccountDto } from './update-account.dto'; import { UpdateAccountDto } from './update-account.dto';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('account') @Controller('account')
export class AccountController { export class AccountController {
@ -48,16 +49,8 @@ export class AccountController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteAccount)
public async deleteAccount(@Param('id') id: string): Promise<AccountModel> { public async deleteAccount(@Param('id') id: string): Promise<AccountModel> {
if (
!hasPermission(this.request.user.permissions, permissions.deleteAccount)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const account = await this.accountService.accountWithOrders( const account = await this.accountService.accountWithOrders(
{ {
id_userId: { id_userId: {
@ -135,17 +128,10 @@ export class AccountController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.createAccount)
public async createAccount( public async createAccount(
@Body() data: CreateAccountDto @Body() data: CreateAccountDto
): Promise<AccountModel> { ): Promise<AccountModel> {
if (
!hasPermission(this.request.user.permissions, permissions.createAccount)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
if (data.platformId) { if (data.platformId) {
const platformId = data.platformId; const platformId = data.platformId;
@ -174,17 +160,10 @@ export class AccountController {
@Post('transfer-balance') @Post('transfer-balance')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.updateAccount)
public async transferAccountBalance( public async transferAccountBalance(
@Body() { accountIdFrom, accountIdTo, balance }: TransferBalanceDto @Body() { accountIdFrom, accountIdTo, balance }: TransferBalanceDto
) { ) {
if (
!hasPermission(this.request.user.permissions, permissions.updateAccount)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const accountsOfUser = await this.accountService.getAccounts( const accountsOfUser = await this.accountService.getAccounts(
this.request.user.id this.request.user.id
@ -236,15 +215,8 @@ export class AccountController {
@Put(':id') @Put(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.updateAccount)
public async update(@Param('id') id: string, @Body() data: UpdateAccountDto) { public async update(@Param('id') id: string, @Body() data: UpdateAccountDto) {
if (
!hasPermission(this.request.user.permissions, permissions.updateAccount)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const originalAccount = await this.accountService.account({ const originalAccount = await this.accountService.account({
id_userId: { id_userId: {

195
apps/api/src/app/admin/admin.controller.ts

@ -47,6 +47,7 @@ import { AdminService } from './admin.service';
import { UpdateAssetProfileDto } from './update-asset-profile.dto'; import { UpdateAssetProfileDto } from './update-asset-profile.dto';
import { UpdateBulkMarketDataDto } from './update-bulk-market-data.dto'; import { UpdateBulkMarketDataDto } from './update-bulk-market-data.dto';
import { UpdateMarketDataDto } from './update-market-data.dto'; import { UpdateMarketDataDto } from './update-market-data.dto';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('admin') @Controller('admin')
export class AdminController { export class AdminController {
@ -60,55 +61,22 @@ export class AdminController {
@Get() @Get()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async getAdminData(): Promise<AdminData> { public async getAdminData(): Promise<AdminData> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.adminService.get(); return this.adminService.get();
} }
@Post('gather') @Post('gather')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async gather7Days(): Promise<void> { public async gather7Days(): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
this.dataGatheringService.gather7Days(); this.dataGatheringService.gather7Days();
} }
@Post('gather/max') @Post('gather/max')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async gatherMax(): Promise<void> { public async gatherMax(): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const uniqueAssets = await this.dataGatheringService.getUniqueAssets(); const uniqueAssets = await this.dataGatheringService.getUniqueAssets();
await this.dataGatheringService.addJobsToQueue( await this.dataGatheringService.addJobsToQueue(
@ -132,19 +100,8 @@ export class AdminController {
@Post('gather/profile-data') @Post('gather/profile-data')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async gatherProfileData(): Promise<void> { public async gatherProfileData(): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const uniqueAssets = await this.dataGatheringService.getUniqueAssets(); const uniqueAssets = await this.dataGatheringService.getUniqueAssets();
await this.dataGatheringService.addJobsToQueue( await this.dataGatheringService.addJobsToQueue(
@ -166,22 +123,11 @@ export class AdminController {
@Post('gather/profile-data/:dataSource/:symbol') @Post('gather/profile-data/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async gatherProfileDataForSymbol( public async gatherProfileDataForSymbol(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<void> { ): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
await this.dataGatheringService.addJobToQueue({ await this.dataGatheringService.addJobToQueue({
data: { data: {
dataSource, dataSource,
@ -197,22 +143,11 @@ export class AdminController {
@Post('gather/:dataSource/:symbol') @Post('gather/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async gatherSymbol( public async gatherSymbol(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<void> { ): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
this.dataGatheringService.gatherSymbol({ dataSource, symbol }); this.dataGatheringService.gatherSymbol({ dataSource, symbol });
return; return;
@ -220,23 +155,12 @@ export class AdminController {
@Post('gather/:dataSource/:symbol/:dateString') @Post('gather/:dataSource/:symbol/:dateString')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async gatherSymbolForDate( public async gatherSymbolForDate(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('dateString') dateString: string, @Param('dateString') dateString: string,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<MarketData> { ): Promise<MarketData> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const date = parseISO(dateString); const date = parseISO(dateString);
if (!isDate(date)) { if (!isDate(date)) {
@ -255,6 +179,7 @@ export class AdminController {
@Get('market-data') @Get('market-data')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async getMarketData( public async getMarketData(
@Query('assetSubClasses') filterByAssetSubClasses?: string, @Query('assetSubClasses') filterByAssetSubClasses?: string,
@Query('presetId') presetId?: MarketDataPreset, @Query('presetId') presetId?: MarketDataPreset,
@ -264,18 +189,6 @@ export class AdminController {
@Query('sortDirection') sortDirection?: Prisma.SortOrder, @Query('sortDirection') sortDirection?: Prisma.SortOrder,
@Query('take') take?: number @Query('take') take?: number
): Promise<AdminMarketData> { ): Promise<AdminMarketData> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const filters = this.apiService.buildFiltersFromQueryParams({ const filters = this.apiService.buildFiltersFromQueryParams({
filterByAssetSubClasses, filterByAssetSubClasses,
filterBySearchQuery filterBySearchQuery
@ -293,44 +206,22 @@ export class AdminController {
@Get('market-data/:dataSource/:symbol') @Get('market-data/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async getMarketDataBySymbol( public async getMarketDataBySymbol(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<AdminMarketDataDetails> { ): Promise<AdminMarketDataDetails> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.adminService.getMarketDataBySymbol({ dataSource, symbol }); return this.adminService.getMarketDataBySymbol({ dataSource, symbol });
} }
@Post('market-data/:dataSource/:symbol') @Post('market-data/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async updateMarketData( public async updateMarketData(
@Body() data: UpdateBulkMarketDataDto, @Body() data: UpdateBulkMarketDataDto,
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
) { ) {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const dataBulkUpdate: Prisma.MarketDataUpdateInput[] = data.marketData.map( const dataBulkUpdate: Prisma.MarketDataUpdateInput[] = data.marketData.map(
({ date, marketPrice }) => ({ ({ date, marketPrice }) => ({
dataSource, dataSource,
@ -351,24 +242,13 @@ export class AdminController {
*/ */
@Put('market-data/:dataSource/:symbol/:dateString') @Put('market-data/:dataSource/:symbol/:dateString')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async update( public async update(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('dateString') dateString: string, @Param('dateString') dateString: string,
@Param('symbol') symbol: string, @Param('symbol') symbol: string,
@Body() data: UpdateMarketDataDto @Body() data: UpdateMarketDataDto
) { ) {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const date = parseISO(dateString); const date = parseISO(dateString);
return this.marketDataService.updateMarketData({ return this.marketDataService.updateMarketData({
@ -385,22 +265,12 @@ export class AdminController {
@Post('profile-data/:dataSource/:symbol') @Post('profile-data/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
@UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor)
public async addProfileData( public async addProfileData(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<SymbolProfile | never> { ): Promise<SymbolProfile | never> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.adminService.addAssetProfile({ return this.adminService.addAssetProfile({
dataSource, dataSource,
symbol, symbol,
@ -410,44 +280,22 @@ export class AdminController {
@Delete('profile-data/:dataSource/:symbol') @Delete('profile-data/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async deleteProfileData( public async deleteProfileData(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<void> { ): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.adminService.deleteProfileData({ dataSource, symbol }); return this.adminService.deleteProfileData({ dataSource, symbol });
} }
@Patch('profile-data/:dataSource/:symbol') @Patch('profile-data/:dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async patchAssetProfileData( public async patchAssetProfileData(
@Body() assetProfileData: UpdateAssetProfileDto, @Body() assetProfileData: UpdateAssetProfileDto,
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
): Promise<EnhancedSymbolProfile> { ): Promise<EnhancedSymbolProfile> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.adminService.patchAssetProfileData({ return this.adminService.patchAssetProfileData({
...assetProfileData, ...assetProfileData,
dataSource, dataSource,
@ -457,22 +305,11 @@ export class AdminController {
@Put('settings/:key') @Put('settings/:key')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async updateProperty( public async updateProperty(
@Param('key') key: string, @Param('key') key: string,
@Body() data: PropertyDto @Body() data: PropertyDto
) { ) {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return await this.adminService.putSetting(key, data.value); return await this.adminService.putSetting(key, data.value);
} }
} }

44
apps/api/src/app/admin/queue/queue.controller.ts

@ -1,11 +1,10 @@
import { AdminJobs } from '@ghostfolio/common/interfaces'; import { AdminJobs } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Controller, Controller,
Delete, Delete,
Get, Get,
HttpException,
Inject, Inject,
Param, Param,
Query, Query,
@ -14,9 +13,9 @@ import {
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { JobStatus } from 'bull'; import { JobStatus } from 'bull';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { QueueService } from './queue.service'; import { QueueService } from './queue.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('admin/queue') @Controller('admin/queue')
export class QueueController { export class QueueController {
@ -27,61 +26,28 @@ export class QueueController {
@Delete('job') @Delete('job')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async deleteJobs( public async deleteJobs(
@Query('status') filterByStatus?: string @Query('status') filterByStatus?: string
): Promise<void> { ): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const status = <JobStatus[]>filterByStatus?.split(',') ?? undefined; const status = <JobStatus[]>filterByStatus?.split(',') ?? undefined;
return this.queueService.deleteJobs({ status }); return this.queueService.deleteJobs({ status });
} }
@Get('job') @Get('job')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async getJobs( public async getJobs(
@Query('status') filterByStatus?: string @Query('status') filterByStatus?: string
): Promise<AdminJobs> { ): Promise<AdminJobs> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const status = <JobStatus[]>filterByStatus?.split(',') ?? undefined; const status = <JobStatus[]>filterByStatus?.split(',') ?? undefined;
return this.queueService.getJobs({ status }); return this.queueService.getJobs({ status });
} }
@Delete('job/:id') @Delete('job/:id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async deleteJob(@Param('id') id: string): Promise<void> { public async deleteJob(@Param('id') id: string): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.queueService.deleteJob(id); return this.queueService.deleteJob(id);
} }
} }

14
apps/api/src/app/app.module.ts

@ -41,6 +41,8 @@ import { SubscriptionModule } from './subscription/subscription.module';
import { SymbolModule } from './symbol/symbol.module'; import { SymbolModule } from './symbol/symbol.module';
import { TagModule } from './tag/tag.module'; import { TagModule } from './tag/tag.module';
import { UserModule } from './user/user.module'; import { UserModule } from './user/user.module';
import { APP_GUARD } from '@nestjs/core';
import { HasPermissionGuard } from '../guards/has-permission.guard';
@Module({ @Module({
imports: [ imports: [
@ -91,7 +93,7 @@ import { UserModule } from './user/user.module';
if (SUPPORTED_LANGUAGE_CODES.includes(code)) { if (SUPPORTED_LANGUAGE_CODES.includes(code)) {
languageCode = code; languageCode = code;
} }
} catch {} } catch { }
res.set('Location', `/${languageCode}`); res.set('Location', `/${languageCode}`);
res.statusCode = StatusCodes.MOVED_PERMANENTLY; res.statusCode = StatusCodes.MOVED_PERMANENTLY;
@ -107,6 +109,12 @@ import { UserModule } from './user/user.module';
UserModule UserModule
], ],
controllers: [AppController], controllers: [AppController],
providers: [CronService] providers: [
CronService,
{
provide: APP_GUARD,
useClass: HasPermissionGuard
}
]
}) })
export class AppModule {} export class AppModule { }

18
apps/api/src/app/auth-device/auth-device.controller.ts

@ -1,17 +1,16 @@
import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.service'; import { AuthDeviceService } from '@ghostfolio/api/app/auth-device/auth-device.service';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Controller, Controller,
Delete, Delete,
HttpException,
Inject, Inject,
Param, Param,
UseGuards UseGuards
} from '@nestjs/common'; } from '@nestjs/common';
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@Controller('auth-device') @Controller('auth-device')
export class AuthDeviceController { export class AuthDeviceController {
@ -22,19 +21,8 @@ export class AuthDeviceController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteAuthDevice)
public async deleteAuthDevice(@Param('id') id: string): Promise<void> { public async deleteAuthDevice(@Param('id') id: string): Promise<void> {
if (
!hasPermission(
this.request.user.permissions,
permissions.deleteAuthDevice
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
await this.authDeviceService.deleteAuthDevice({ id }); await this.authDeviceService.deleteAuthDevice({ id });
} }
} }

29
apps/api/src/app/benchmark/benchmark.controller.ts

@ -5,7 +5,7 @@ import type {
BenchmarkResponse, BenchmarkResponse,
UniqueAsset UniqueAsset
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Body, Body,
@ -25,6 +25,7 @@ import { DataSource } from '@prisma/client';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { BenchmarkService } from './benchmark.service'; import { BenchmarkService } from './benchmark.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('benchmark') @Controller('benchmark')
export class BenchmarkController { export class BenchmarkController {
@ -35,19 +36,8 @@ export class BenchmarkController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async addBenchmark(@Body() { dataSource, symbol }: UniqueAsset) { public async addBenchmark(@Body() { dataSource, symbol }: UniqueAsset) {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
try { try {
const benchmark = await this.benchmarkService.addBenchmark({ const benchmark = await this.benchmarkService.addBenchmark({
dataSource, dataSource,
@ -72,22 +62,11 @@ export class BenchmarkController {
@Delete(':dataSource/:symbol') @Delete(':dataSource/:symbol')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.accessAdminControl)
public async deleteBenchmark( public async deleteBenchmark(
@Param('dataSource') dataSource: DataSource, @Param('dataSource') dataSource: DataSource,
@Param('symbol') symbol: string @Param('symbol') symbol: string
) { ) {
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
try { try {
const benchmark = await this.benchmarkService.deleteBenchmark({ const benchmark = await this.benchmarkService.deleteBenchmark({
dataSource, dataSource,

22
apps/api/src/app/cache/cache.controller.ts

@ -1,39 +1,29 @@
import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Controller, Controller,
HttpException,
Inject, Inject,
Post, Post,
UseGuards UseGuards
} from '@nestjs/common'; } from '@nestjs/common';
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@Controller('cache') @Controller('cache')
export class CacheController { export class CacheController {
public constructor( public constructor(
private readonly redisCacheService: RedisCacheService, private readonly redisCacheService: RedisCacheService,
@Inject(REQUEST) private readonly request: RequestWithUser @Inject(REQUEST) private readonly request: RequestWithUser
) {} ) { }
@Post('flush') @Post('flush')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
public async flushCache(): Promise<void> { @HasPermission(permissions.accessAdminControl) // permission needed
if (
!hasPermission(
this.request.user.permissions,
permissions.accessAdminControl
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
public async flushCache(): Promise<void> {
return this.redisCacheService.reset(); return this.redisCacheService.reset();
} }
} }

6
apps/api/src/app/import/import.controller.ts

@ -24,6 +24,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { ImportDataDto } from './import-data.dto'; import { ImportDataDto } from './import-data.dto';
import { ImportService } from './import.service'; import { ImportService } from './import.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('import') @Controller('import')
export class ImportController { export class ImportController {
@ -35,6 +36,7 @@ export class ImportController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.createAccount)
@UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor)
@UseInterceptors(TransformDataSourceInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor)
public async import( public async import(
@ -42,10 +44,6 @@ export class ImportController {
@Query('dryRun') isDryRun?: boolean @Query('dryRun') isDryRun?: boolean
): Promise<ImportResponse> { ): Promise<ImportResponse> {
if ( if (
!hasPermission(
this.request.user.permissions,
permissions.createAccount
) ||
!hasPermission(this.request.user.permissions, permissions.createOrder) !hasPermission(this.request.user.permissions, permissions.createOrder)
) { ) {
throw new HttpException( throw new HttpException(

23
apps/api/src/app/order/order.controller.ts

@ -32,6 +32,7 @@ import { CreateOrderDto } from './create-order.dto';
import { Activities } from './interfaces/activities.interface'; import { Activities } from './interfaces/activities.interface';
import { OrderService } from './order.service'; import { OrderService } from './order.service';
import { UpdateOrderDto } from './update-order.dto'; import { UpdateOrderDto } from './update-order.dto';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('order') @Controller('order')
export class OrderController { export class OrderController {
@ -45,16 +46,8 @@ export class OrderController {
@Delete() @Delete()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteOrder)
public async deleteOrders(): Promise<number> { public async deleteOrders(): Promise<number> {
if (
!hasPermission(this.request.user.permissions, permissions.deleteOrder)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.orderService.deleteOrders({ return this.orderService.deleteOrders({
userId: this.request.user.id userId: this.request.user.id
}); });
@ -122,17 +115,9 @@ export class OrderController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.createOrder)
@UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor)
public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> { public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> {
if (
!hasPermission(this.request.user.permissions, permissions.createOrder)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const order = await this.orderService.createOrder({ const order = await this.orderService.createOrder({
...data, ...data,
date: parseISO(data.date), date: parseISO(data.date),
@ -172,6 +157,7 @@ export class OrderController {
@Put(':id') @Put(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.updateOrder)
@UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor)
public async update(@Param('id') id: string, @Body() data: UpdateOrderDto) { public async update(@Param('id') id: string, @Body() data: UpdateOrderDto) {
const originalOrder = await this.orderService.order({ const originalOrder = await this.orderService.order({
@ -179,7 +165,6 @@ export class OrderController {
}); });
if ( if (
!hasPermission(this.request.user.permissions, permissions.updateOrder) ||
!originalOrder || !originalOrder ||
originalOrder.userId !== this.request.user.id originalOrder.userId !== this.request.user.id
) { ) {

31
apps/api/src/app/platform/platform.controller.ts

@ -20,6 +20,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { CreatePlatformDto } from './create-platform.dto'; import { CreatePlatformDto } from './create-platform.dto';
import { PlatformService } from './platform.service'; import { PlatformService } from './platform.service';
import { UpdatePlatformDto } from './update-platform.dto'; import { UpdatePlatformDto } from './update-platform.dto';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('platform') @Controller('platform')
export class PlatformController { export class PlatformController {
@ -36,36 +37,20 @@ export class PlatformController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.createPlatform)
public async createPlatform( public async createPlatform(
@Body() data: CreatePlatformDto @Body() data: CreatePlatformDto
): Promise<Platform> { ): Promise<Platform> {
if (
!hasPermission(this.request.user.permissions, permissions.createPlatform)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.platformService.createPlatform(data); return this.platformService.createPlatform(data);
} }
@Put(':id') @Put(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.updatePlatform)
public async updatePlatform( public async updatePlatform(
@Param('id') id: string, @Param('id') id: string,
@Body() data: UpdatePlatformDto @Body() data: UpdatePlatformDto
) { ) {
if (
!hasPermission(this.request.user.permissions, permissions.updatePlatform)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const originalPlatform = await this.platformService.getPlatform({ const originalPlatform = await this.platformService.getPlatform({
id id
}); });
@ -89,16 +74,8 @@ export class PlatformController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deletePlatform)
public async deletePlatform(@Param('id') id: string) { public async deletePlatform(@Param('id') id: string) {
if (
!hasPermission(this.request.user.permissions, permissions.deletePlatform)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const originalPlatform = await this.platformService.getPlatform({ const originalPlatform = await this.platformService.getPlatform({
id id
}); });

25
apps/api/src/app/tag/tag.controller.ts

@ -20,6 +20,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { CreateTagDto } from './create-tag.dto'; import { CreateTagDto } from './create-tag.dto';
import { TagService } from './tag.service'; import { TagService } from './tag.service';
import { UpdateTagDto } from './update-tag.dto'; import { UpdateTagDto } from './update-tag.dto';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('tag') @Controller('tag')
export class TagController { export class TagController {
@ -36,27 +37,15 @@ export class TagController {
@Post() @Post()
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.createTag)
public async createTag(@Body() data: CreateTagDto): Promise<Tag> { public async createTag(@Body() data: CreateTagDto): Promise<Tag> {
if (!hasPermission(this.request.user.permissions, permissions.createTag)) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
return this.tagService.createTag(data); return this.tagService.createTag(data);
} }
@Put(':id') @Put(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.updateTag)
public async updateTag(@Param('id') id: string, @Body() data: UpdateTagDto) { public async updateTag(@Param('id') id: string, @Body() data: UpdateTagDto) {
if (!hasPermission(this.request.user.permissions, permissions.updateTag)) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const originalTag = await this.tagService.getTag({ const originalTag = await this.tagService.getTag({
id id
}); });
@ -80,14 +69,8 @@ export class TagController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteTag)
public async deleteTag(@Param('id') id: string) { public async deleteTag(@Param('id') id: string) {
if (!hasPermission(this.request.user.permissions, permissions.deleteTag)) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
}
const originalTag = await this.tagService.getTag({ const originalTag = await this.tagService.getTag({
id id
}); });

19
apps/api/src/app/user/user.controller.ts

@ -1,6 +1,6 @@
import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service';
import { User, UserSettings } from '@ghostfolio/common/interfaces'; import { User, UserSettings } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types'; import type { RequestWithUser } from '@ghostfolio/common/types';
import { import {
Body, Body,
@ -25,6 +25,7 @@ import { size } from 'lodash';
import { UserItem } from './interfaces/user-item.interface'; import { UserItem } from './interfaces/user-item.interface';
import { UpdateUserSettingDto } from './update-user-setting.dto'; import { UpdateUserSettingDto } from './update-user-setting.dto';
import { UserService } from './user.service'; import { UserService } from './user.service';
import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator';
@Controller('user') @Controller('user')
export class UserController { export class UserController {
@ -37,10 +38,9 @@ export class UserController {
@Delete(':id') @Delete(':id')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.deleteUser)
public async deleteUser(@Param('id') id: string): Promise<UserModel> { public async deleteUser(@Param('id') id: string): Promise<UserModel> {
if ( if (id === this.request.user.id
!hasPermission(this.request.user.permissions, permissions.deleteUser) ||
id === this.request.user.id
) { ) {
throw new HttpException( throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN), getReasonPhrase(StatusCodes.FORBIDDEN),
@ -93,6 +93,7 @@ export class UserController {
@Put('setting') @Put('setting')
@UseGuards(AuthGuard('jwt')) @UseGuards(AuthGuard('jwt'))
@HasPermission(permissions.updateUserSettings)
public async updateUserSetting(@Body() data: UpdateUserSettingDto) { public async updateUserSetting(@Body() data: UpdateUserSettingDto) {
if ( if (
size(data) === 1 && size(data) === 1 &&
@ -100,16 +101,6 @@ export class UserController {
this.request.user.role === 'DEMO' this.request.user.role === 'DEMO'
) { ) {
// Allow benchmark or date range change for demo user // Allow benchmark or date range change for demo user
} else if (
!hasPermission(
this.request.user.permissions,
permissions.updateUserSettings
)
) {
throw new HttpException(
getReasonPhrase(StatusCodes.FORBIDDEN),
StatusCodes.FORBIDDEN
);
} }
const userSettings: UserSettings = { const userSettings: UserSettings = {

10
apps/api/src/guards/has-permission.guard.spec.ts

@ -1,8 +1,6 @@
import { HttpException } from '@nestjs/common'; import { HttpException } from '@nestjs/common';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host'; import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
import { Test, TestingModule } from '@nestjs/testing';
import { HasPermissionGuard } from './has-permission.guard'; import { HasPermissionGuard } from './has-permission.guard';
describe('HasPermissionGuard', () => { describe('HasPermissionGuard', () => {
@ -10,12 +8,8 @@ describe('HasPermissionGuard', () => {
let reflector: Reflector; let reflector: Reflector;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ reflector = new Reflector();
providers: [HasPermissionGuard, Reflector] guard = new HasPermissionGuard(reflector);
}).compile();
guard = module.get<HasPermissionGuard>(HasPermissionGuard);
reflector = module.get<Reflector>(Reflector);
}); });
function setupReflectorSpy(returnValue: string) { function setupReflectorSpy(returnValue: string) {

7
apps/api/src/guards/has-permission.guard.ts

@ -11,9 +11,12 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@Injectable() @Injectable()
export class HasPermissionGuard implements CanActivate { export class HasPermissionGuard implements CanActivate {
public constructor(private reflector: Reflector) {} public constructor(private reflector: Reflector) {
}
public canActivate(context: ExecutionContext): boolean { public canActivate(context: ExecutionContext): boolean {
const { user } = context.switchToHttp().getRequest();
const requiredPermission = this.reflector.get<string>( const requiredPermission = this.reflector.get<string>(
HAS_PERMISSION_KEY, HAS_PERMISSION_KEY,
context.getHandler() context.getHandler()
@ -23,7 +26,7 @@ export class HasPermissionGuard implements CanActivate {
return true; // No specific permissions required return true; // No specific permissions required
} }
const { user } = context.switchToHttp().getRequest();
if (!user || !hasPermission(user.permissions, requiredPermission)) { if (!user || !hasPermission(user.permissions, requiredPermission)) {
throw new HttpException( throw new HttpException(

Loading…
Cancel
Save