diff --git a/devspace.yaml b/devspace.yaml index 652a50f..4713cba 100644 --- a/devspace.yaml +++ b/devspace.yaml @@ -11,14 +11,26 @@ dev: app: imageSelector: ghcr.io/polyflix/video:main devImage: ghcr.io/loft-sh/devspace-containers/typescript:18-alpine + env: + - name: NODE_ENV + value: development + - name: NEST_AUTHORIZATION_READ + value: http://keto-read:80 + - name: NEST_AUTHORIZATION_WRITE + value: http://keto-write:80 + - name: LOG_LEVEL + value: debug sync: - path: ./ excludePaths: - .git/ + - node_modules/ + - dist + - .idea + - x-utils/node_modules + - x-utils/dist uploadExcludePaths: - Dockerfile - - node_modules - - dist terminal: command: ./devcontainer.sh ports: diff --git a/package.json b/package.json index ec559cd..f5eb7a6 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ }, "dependencies": { "@nestjs/axios": "0.0.7", - "@nestjs/common": "^8.0.0", + "@nestjs/common": "8.4.4", "@nestjs/config": "^2.0.0", - "@nestjs/core": "^8.0.0", + "@nestjs/core": "8.4.4", "@nestjs/microservices": "^8.4.4", "@nestjs/platform-express": "^8.0.0", "@nestjs/terminus": "^8.0.6", - "@nestjs/typeorm": "^8.0.3", + "@nestjs/typeorm": "8.0.3", "@opentelemetry/auto-instrumentations-node": "^0.28.0", "@opentelemetry/context-async-hooks": "^1.0.1", "@opentelemetry/core": "^1.0.1", @@ -41,6 +41,7 @@ "@opentelemetry/sdk-node": "^0.27.0", "@opentelemetry/sdk-trace-base": "^1.0.1", "@opentelemetry/semantic-conventions": "^1.0.1", + "@ory/keto-client": "^0.10.0-alpha.0", "@polyflix/x-utils": "^1.8.2", "@svtslv/nestjs-minio": "^1.0.1", "@swan-io/boxed": "^0.8.0", @@ -54,7 +55,7 @@ "nest-winston": "^1.6.2", "nestjs-otel": "^3.0.4", "pg": "^8.7.3", - "reflect-metadata": "^0.1.13", + "reflect-metadata": "0.1.13", "rimraf": "^3.0.2", "rxjs": "^7.2.0", "typeorm": "^0.2.45", diff --git a/src/main/modules/infrastructure/controllers/controllers.module.ts b/src/main/modules/infrastructure/controllers/controllers.module.ts index f05a8ce..d80b4c0 100644 --- a/src/main/modules/infrastructure/controllers/controllers.module.ts +++ b/src/main/modules/infrastructure/controllers/controllers.module.ts @@ -1,12 +1,18 @@ -import { Module } from "@nestjs/common"; +import { Logger, Module } from "@nestjs/common"; import { APP_GUARD } from "@nestjs/core"; -import { RolesGuard } from "@polyflix/x-utils"; +import { + AuthorizationService, + configureAuthZService, + RolesGuard +} from "@polyflix/x-utils"; import { CrudVideoController } from "./crud-video.controller"; import { StatsVideoController } from "./stats-video.controller"; import { MessageVideoController } from "./messages-video.controller"; import { UserController } from "./user.controller"; import { AdminVideoController } from "./admin/video.controller"; import { ReportVideoController } from "./report.controller"; +import { AuthorizationModule } from "@polyflix/x-utils"; +import { ConfigModule, ConfigService } from "@nestjs/config"; @Module({ controllers: [ @@ -23,6 +29,15 @@ import { ReportVideoController } from "./report.controller"; useClass: RolesGuard } ], - imports: [] + imports: [ + AuthorizationModule.register({ + useFactory: (cfgSvc: ConfigService) => { + const config = configureAuthZService(cfgSvc); + return new AuthorizationService(config); + }, + inject: [ConfigService], + imports: [ConfigModule] + }) + ] }) export class ControllersModule {} diff --git a/src/main/modules/infrastructure/controllers/crud-video.controller.ts b/src/main/modules/infrastructure/controllers/crud-video.controller.ts index 77571dc..fa429c3 100644 --- a/src/main/modules/infrastructure/controllers/crud-video.controller.ts +++ b/src/main/modules/infrastructure/controllers/crud-video.controller.ts @@ -23,7 +23,14 @@ import { import { VideoCreateDto } from "../../application/dto/video-create.dto"; import { youtube_v3 } from "googleapis"; import { TokenService } from "../services/token.service"; -import { IsAdmin, MeId, MeRoles, Roles } from "@polyflix/x-utils"; +import { + AuthorizationService, + IsAdmin, + MeId, + MeRoles, + Role, + Roles +} from "@polyflix/x-utils"; import { PresignedUrlResponse } from "../../../core/types/presigned-url.type"; import { MINIO_BUCKETS } from "../../../core/constants/presignedUrl.constant"; import { PresignedUrl } from "../../domain/models/presigned-url.entity"; @@ -32,7 +39,7 @@ import { Paginate } from "src/main/core/types/pagination.dto"; import { VideoUpdateDto } from "../../application/dto/video-update.dto"; import { LikeService } from "../services/like.service"; import { Span } from "nestjs-otel"; -import { Role } from "@polyflix/x-utils/dist/types/roles.enum"; +import { Visibility } from "../adapters/repositories/entities/content.model"; @Controller("videos") export class CrudVideoController { @@ -42,7 +49,8 @@ export class CrudVideoController { private readonly likeService: LikeService, private readonly videoApiMapper: VideoApiMapper, private readonly presignedUrlApiMapper: PresignedUrlApiMapper, - private readonly tokenService: TokenService + private readonly tokenService: TokenService, + private readonly authorizationService: AuthorizationService ) {} @Post() @@ -71,6 +79,16 @@ export class CrudVideoController { this.presignedUrlApiMapper.entityToApi(thumbnailPutPsu); } + if (response.visibility === Visibility.PUBLIC) { + await this.authorizationService.setVideoPublic(response.id); + } + + await this.authorizationService.writeOwnerToVideo(meId, response.id); + await this.authorizationService.writeOwnerRoleToVideo( + Role.Admin, + response.id + ); + return response; } @@ -132,6 +150,10 @@ export class CrudVideoController { ): Promise { const video: Video = await this.videoService.findOne(slug, userId); + if (!(await this.authorizationService.canViewVideo(userId, video.id))) { + throw new ForbiddenException(`You cannot view this video`); + } + if (!isAdmin && Video.canAccessVideo(video, userId).isError()) { throw new UnauthorizedException(`You cannot access this video`); } diff --git a/src/resources/application.yml b/src/resources/application.yml index 1f782ae..a9ca538 100644 --- a/src/resources/application.yml +++ b/src/resources/application.yml @@ -5,6 +5,11 @@ telemetry: port: 4317 host: localhost +authorization: + read: http://localhost:4466 + write: http://localhost:4467 +# apikey: yourApikey + kafka: topics: video: polyflix.video