Skip to content

Commit

Permalink
🔒 Implement guard to admin routes to force the use of the admin key f…
Browse files Browse the repository at this point in the history
…rom .env
  • Loading branch information
Xen0Xys committed May 15, 2024
1 parent a69973b commit 8b5a9e0
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ SSL_CERT_FILE=""

# API
PREFIX="api/v1/"

# Security
ADMIN_KEY="admin"
12 changes: 10 additions & 2 deletions src/modules/webtoon/admin/admin.controller.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,63 @@
import {Body, Controller, Delete, Get, HttpCode, Post} from "@nestjs/common";
import {ApiResponse, ApiTags} from "@nestjs/swagger";
import {Body, Controller, Delete, Get, HttpCode, Post, UseGuards} from "@nestjs/common";
import {ApiBearerAuth, ApiResponse, ApiTags} from "@nestjs/swagger";
import {DownloadManagerService} from "../webtoon/download-manager.service";
import {AddWebtoonToQueueDto} from "./models/dto/add-webtoon-to-queue.dto";
import {HttpStatusCode} from "axios";
import CachedWebtoonModel from "../webtoon/models/models/cached-webtoon.model";
import {AdminGuard} from "./guard/admin.guard";


@Controller("admin")
@ApiTags("Admin")
@UseGuards(AdminGuard)
export class AdminController{

constructor(
private readonly downloadManagerService: DownloadManagerService,
){}

@Post("queue")
@ApiBearerAuth()
@ApiResponse({status: HttpStatusCode.Created, description: "Adds a webtoon to the download queue"})
@ApiResponse({status: HttpStatusCode.TooEarly, description: "Cache not loaded."})
async addWebtoonToQueue(@Body() addWebtoonToQueueDto: AddWebtoonToQueueDto): Promise<void>{
return this.downloadManagerService.addWebtoonToQueue(addWebtoonToQueueDto.name, addWebtoonToQueueDto.language);
}

@Post("update/all")
@ApiBearerAuth()
@ApiResponse({status: HttpStatusCode.Created, description: "Updates all webtoons in the database"})
@ApiResponse({status: HttpStatusCode.TooEarly, description: "Cache not loaded."})
async updateAllWebtoons(): Promise<void>{
return this.downloadManagerService.updateAllWebtoons();
}

@Get("current-download")
@ApiBearerAuth()
@ApiResponse({status: HttpStatusCode.Ok, description: "Returns the current download"})
@ApiResponse({status: HttpStatusCode.NotFound, description: "No download in progress"})
async getCurrentDownload(): Promise<CachedWebtoonModel>{
return this.downloadManagerService.getCurrentDownload();
}

@Get("queue")
@ApiBearerAuth()
@ApiResponse({status: HttpStatusCode.Ok, description: "Returns the current download queue"})
@ApiResponse({status: HttpStatusCode.NotFound, description: "No download in progress"})
async getQueue(): Promise<CachedWebtoonModel[]>{
return this.downloadManagerService.getDownloadQueue();
}

@Delete("current-download")
@ApiBearerAuth()
@HttpCode(HttpStatusCode.NoContent)
@ApiResponse({status: HttpStatusCode.NoContent, description: "Cancels the current download"})
async cancelCurrentDownload(): Promise<void>{
return this.downloadManagerService.skipCurrentDownload();
}

@Delete("queue")
@ApiBearerAuth()
@HttpCode(HttpStatusCode.NoContent)
@ApiResponse({status: HttpStatusCode.NoContent, description: "Clears the download queue"})
async clearQueue(): Promise<void>{
Expand Down
3 changes: 2 additions & 1 deletion src/modules/webtoon/admin/admin.module.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import {Module} from "@nestjs/common";
import {AdminController} from "./admin.controller";
import {WebtoonModule} from "../webtoon/webtoon.module";
import {AdminGuard} from "./guard/admin.guard";

@Module({
imports: [WebtoonModule],
controllers: [AdminController],
providers: [],
providers: [AdminGuard],
})
export class AdminModule{}
20 changes: 20 additions & 0 deletions src/modules/webtoon/admin/guard/admin.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {CanActivate, ExecutionContext, Injectable, UnauthorizedException} from "@nestjs/common";
import {ConfigService} from "@nestjs/config";

@Injectable()
export class AdminGuard implements CanActivate{
constructor(
private readonly configService: ConfigService,
){}

async canActivate(context: ExecutionContext): Promise<boolean>{
const adminKey = this.configService.get("ADMIN_KEY");
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(" ")[1];
if(!token)
throw new UnauthorizedException("No token provided");
if(token !== adminKey)
throw new UnauthorizedException("Invalid token");
return true;
}
}

0 comments on commit 8b5a9e0

Please sign in to comment.