diff --git a/server/src/assets/assets.controller.ts b/server/src/assets/assets.controller.ts index 60c65869..8a7d24f7 100644 --- a/server/src/assets/assets.controller.ts +++ b/server/src/assets/assets.controller.ts @@ -13,6 +13,7 @@ import { Request, } from '@nestjs/common'; import { CookieAuthGuard } from '../auth/guards/cookie-auth.guard'; +import { IsOrgAuthGuard } from '../auth/guards/is-org-auth.guard'; import { DeleteResult } from 'typeorm'; import type { Request as ExpressRequest } from 'express'; @@ -28,7 +29,7 @@ import { User } from '../users/entities/user.entity'; export class AssetsController { constructor(private readonly assetsService: AssetsService) {} - @UseGuards(CookieAuthGuard) + @UseGuards(IsOrgAuthGuard) @Post() async create( @Request() request: ExpressRequest, diff --git a/server/src/assets/assets.module.ts b/server/src/assets/assets.module.ts index bf602d31..2494eedf 100644 --- a/server/src/assets/assets.module.ts +++ b/server/src/assets/assets.module.ts @@ -1,12 +1,14 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; + import { AssetsService } from './assets.service'; import { AssetsController } from './assets.controller'; import { Asset } from './entities/asset.entity'; import { AuthModule } from '../auth/auth.module'; +import { UserOrganizationsModule } from '../user-org/user-org.module'; @Module({ - imports: [TypeOrmModule.forFeature([Asset]), AuthModule], + imports: [TypeOrmModule.forFeature([Asset]), UserOrganizationsModule, AuthModule], controllers: [AssetsController], providers: [AssetsService], exports: [AssetsService], diff --git a/server/src/assets/dto/create-asset.dto.ts b/server/src/assets/dto/create-asset.dto.ts index 2ec56abe..5653f6e6 100644 --- a/server/src/assets/dto/create-asset.dto.ts +++ b/server/src/assets/dto/create-asset.dto.ts @@ -9,7 +9,7 @@ export class CreateAssetDto { @IsNotEmpty() description: string; - @IsOptional() + @IsNotEmpty() quantity: number; @IsOptional() diff --git a/server/src/auth/auth.module.ts b/server/src/auth/auth.module.ts index 2d59573c..988b9e3c 100644 --- a/server/src/auth/auth.module.ts +++ b/server/src/auth/auth.module.ts @@ -8,6 +8,8 @@ import { UsersModule } from '../users/users.module'; import { LoginStrategy } from './strategies/login.strategy'; import { CookieStrategy } from './strategies/cookie.strategy'; import { WSCookieStrategy } from './strategies/ws-cookie..strategy'; +// import { UserOrganizationsService } from '../user-org/user-org.service'; +import { UserOrganizationsModule } from '../user-org/user-org.module'; @Module({ controllers: [AuthController], @@ -19,6 +21,7 @@ import { WSCookieStrategy } from './strategies/ws-cookie..strategy'; secret: process.env.JWT_SECRET, signOptions: { expiresIn: '60s' }, }), + UserOrganizationsModule, ], providers: [AuthService, LoginStrategy, CookieStrategy, WSCookieStrategy], }) diff --git a/server/src/auth/guards/cookie-auth.guard.ts b/server/src/auth/guards/cookie-auth.guard.ts index fb0a1104..3667535e 100644 --- a/server/src/auth/guards/cookie-auth.guard.ts +++ b/server/src/auth/guards/cookie-auth.guard.ts @@ -1,6 +1,5 @@ import { ExecutionContext, Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; -import { Observable } from 'rxjs'; import { JwtService } from '@nestjs/jwt'; import { COOKIE_KEY } from '../constants'; diff --git a/server/src/auth/guards/is-org-auth.guard.ts b/server/src/auth/guards/is-org-auth.guard.ts new file mode 100644 index 00000000..6c31827f --- /dev/null +++ b/server/src/auth/guards/is-org-auth.guard.ts @@ -0,0 +1,46 @@ +import { ExecutionContext, Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; +import { JwtService } from '@nestjs/jwt'; + +import { COOKIE_KEY } from '../constants'; +import { CookieStrategy } from '../strategies/cookie.strategy'; +import { UserOrganizationsService } from '../../user-org/user-org.service'; + +import type { User } from '../../users/entities/user.entity'; + +@Injectable() +export class IsOrgAuthGuard extends AuthGuard() { + constructor(private jwtService: JwtService, private userOrgService: UserOrganizationsService) { + super({ defaultStrategy: CookieStrategy }); + } + + async canActivate(context: ExecutionContext): Promise { + const request = context.switchToHttp().getRequest(); + const jwt = request.signedCookies[COOKIE_KEY]; + + if (!jwt) { + return false; + } + + let user: User = {} as User; + try { + user = await this.jwtService.verify(jwt, { secret: process.env.JWT_SECRET }); + const userOrgs = await this.userOrgService.getAllByUserId(user.id); + + // check that the user has an org to post on behalf of + // check that there is only 1 org (temp) + // temp - only allow posts from users that only have 1 org + // - created relationship as many to many for future fleixbility + // but only want a 1to1 user<>org relationship for now + if (userOrgs.length !== 1) { + return false; + } + + request.user = user; + + return true; + } catch (_e) { + return false; + } + } +} diff --git a/server/src/user-org/user-org.service.ts b/server/src/user-org/user-org.service.ts index a75c4b68..ef458afb 100644 --- a/server/src/user-org/user-org.service.ts +++ b/server/src/user-org/user-org.service.ts @@ -59,6 +59,17 @@ export class UserOrganizationsService { return userOrg; } + async getAllByUserId(userId: number): Promise { + const userOrgs = await this.userOrganizationsRepository.find({ + where: { + user: { + id: userId, + }, + }, + }); + return userOrgs; + } + async update( id: number, updateUserOrganizationsDto: UpdateUserOrganizationDto, diff --git a/server/test/assets/assets.e2e-spec.ts b/server/test/assets/assets.e2e-spec.ts index d6d63183..ca48e8bf 100644 --- a/server/test/assets/assets.e2e-spec.ts +++ b/server/test/assets/assets.e2e-spec.ts @@ -15,6 +15,7 @@ import { CreateUserDto } from '../../src/users/dto/create-user.dto'; import { UsersModule } from '../../src/users/users.module'; import { UsersService } from '../../src/users/users.service'; import { AuthModule } from '../../src/auth/auth.module'; +import { UserOrganizationsModule } from '../../src/user-org/user-org.module'; import * as cookieParser from 'cookie-parser'; describe('AssetsController', () => { @@ -28,7 +29,7 @@ describe('AssetsController', () => { beforeAll(async () => { const module: TestingModule = await Test.createTestingModule({ - imports: [AssetsModule, UsersModule, AuthModule, TypeOrmModule.forRoot(TEST_DB_OPTIONS)], + imports: [AssetsModule, UsersModule, AuthModule, TypeOrmModule.forRoot(TEST_DB_OPTIONS), UserOrganizationsModule], controllers: [AssetsController], providers: [{ provide: getRepositoryToken(Asset), useClass: Repository }], }).compile();