From 9f85c11d2ea14e67375c8df4e031ac470923aa5b Mon Sep 17 00:00:00 2001 From: Jurgis Sakalauskas Date: Mon, 5 Dec 2022 20:38:29 +0200 Subject: [PATCH] Static module: extract logic from controller to service --- src/Static/static.controller.ts | 97 ++------------------------------- src/Static/static.module.ts | 3 +- src/Static/static.service.ts | 88 ++++++++++++++++++++++++++++++ src/app.module.ts | 18 +----- tsconfig.json | 3 +- 5 files changed, 99 insertions(+), 110 deletions(-) create mode 100644 src/Static/static.service.ts diff --git a/src/Static/static.controller.ts b/src/Static/static.controller.ts index 64e66f9..d5f4a31 100644 --- a/src/Static/static.controller.ts +++ b/src/Static/static.controller.ts @@ -1,106 +1,21 @@ -import { - Controller, - Get, - Next, - NotFoundException, - Req, - Res, - UnauthorizedException, -} from '@nestjs/common'; +import { Controller, Get, Next, Req, Res } from '@nestjs/common'; import { NextFunction, Request, Response } from 'express'; -import { readdir, stat } from 'fs/promises'; -import { join } from 'path'; -import { Stats } from 'fs'; +import { StaticService } from './static.service'; @Controller('*') export class StaticController { + constructor(private readonly staticService: StaticService) {} @Get() async main( @Req() request: Request, @Res() response: Response, @Next() next: NextFunction, ) { - //todo - refactor to use service - const relPath = request.url; - //relPath = relPath.split('%2E').join('.'); - //relPath = relPath.split('%2e').join('.'); - - if (relPath.indexOf('..') > -1) { - throw new UnauthorizedException( - 'You are not authorized to visit ' + request.url, - ); - } - - const path = join(__dirname, process.env.STATIC_SERVE_FOLDER, relPath); - - const stats: Stats | false = await stat(path).catch(() => false); - - if (stats === false) { - throw new NotFoundException('Path not found: ' + relPath); - } - - if (!stats.isDirectory()) { + const dirIndexHtml = await this.staticService.provideDirIndex(request.url); + if (dirIndexHtml === null) { return next(); } - response.status(200).send(await readDirectory(path, relPath)); - - return; + return response.status(200).send(dirIndexHtml); } } - -//todo - move this to service -async function readDirectory(path: string, relPath: string) { - let files = await readdir(path); - let longestFileLength = 0; - - files = files.filter((fileName: string) => { - const fileIncluded = fileName[0] !== '.'; - longestFileLength = - fileIncluded && longestFileLength < fileName.length - ? fileName.length - : longestFileLength; - - return fileIncluded; - }); - - longestFileLength += 10; - - let result: string; - const resultHtmlStart = ` - - Index of ${relPath} - -

Index of ${relPath}

-
`;
-
-  result = `../`;
-
-  for (const file of files) {
-    const stats: Stats | false = await stat(join(path, file)).catch(
-      () => false,
-    );
-
-    if (stats === false) {
-      continue;
-    }
-    const arrDate: Array = stats.birthtime.toUTCString().split(' ');
-    const strDate: string =
-      ' '.repeat(longestFileLength - file.length) +
-      `${arrDate[1]}-${arrDate[2]}-${arrDate[3]} ${arrDate[4]}`;
-
-    if (stats.isDirectory()) {
-      const strSize = ' '.repeat(19) + '-';
-      result += '\n' + `${file}/${strDate + strSize}`;
-      continue;
-    }
-    let strSize = stats.size.toString();
-    strSize = ' '.repeat(20 - strSize.length) + strSize;
-
-    result += '\n' + `${file} ${strDate + strSize}`;
-  }
-
-  const resultHtmlEnd = `

`; - - return resultHtmlStart + result + resultHtmlEnd; -} diff --git a/src/Static/static.module.ts b/src/Static/static.module.ts index d450c0c..f9dc129 100644 --- a/src/Static/static.module.ts +++ b/src/Static/static.module.ts @@ -8,6 +8,7 @@ import { ServeStaticModule } from '@nestjs/serve-static'; import { join } from 'path'; import { StaticController } from './static.controller'; import { RemoveQueryUrlRewriteMiddleware } from './UrlRewrite/url-rewrite.middleware'; +import { StaticService } from './static.service'; @Module({ imports: [ @@ -16,7 +17,7 @@ import { RemoveQueryUrlRewriteMiddleware } from './UrlRewrite/url-rewrite.middle }), ], controllers: [StaticController], - providers: [], + providers: [StaticService], }) export class StaticModule implements NestModule { configure(consumer: MiddlewareConsumer) { diff --git a/src/Static/static.service.ts b/src/Static/static.service.ts new file mode 100644 index 0000000..b76d224 --- /dev/null +++ b/src/Static/static.service.ts @@ -0,0 +1,88 @@ +import { + Injectable, + NotFoundException, + UnauthorizedException, +} from '@nestjs/common'; +import { readdir, stat } from 'fs/promises'; +import { Stats } from 'fs'; +import { join } from 'path'; + +@Injectable() +export class StaticService { + async provideDirIndex(relPath: string): Promise { + if (relPath.indexOf('..') > -1) { + throw new UnauthorizedException( + 'You are not authorized to visit ' + relPath, + ); + } + + const path = join(__dirname, process.env.STATIC_SERVE_FOLDER, relPath); + + const stats: Stats | false = await stat(path).catch(() => false); + + if (stats === false) { + throw new NotFoundException('Path not found: ' + relPath); + } + + if (!stats.isDirectory()) { + return null; + } + + return this.readDirectory(path, relPath); + } + + private async readDirectory(path: string, relPath: string) { + let files = await readdir(path); + let longestFileLength = 0; + + files = files.filter((fileName: string) => { + const fileIncluded = fileName[0] !== '.'; + longestFileLength = + fileIncluded && longestFileLength < fileName.length + ? fileName.length + : longestFileLength; + + return fileIncluded; + }); + + longestFileLength += 10; + + let result: string; + const resultHtmlStart = ` + + Index of ${relPath} + +

Index of ${relPath}

+
`;
+
+    result = `../`;
+
+    for (const file of files) {
+      const stats: Stats | false = await stat(join(path, file)).catch(
+        () => false,
+      );
+
+      if (stats === false) {
+        continue;
+      }
+      const arrDate: Array = stats.birthtime.toUTCString().split(' ');
+      const strDate: string =
+        ' '.repeat(longestFileLength - file.length) +
+        `${arrDate[1]}-${arrDate[2]}-${arrDate[3]} ${arrDate[4]}`;
+
+      if (stats.isDirectory()) {
+        const strSize = ' '.repeat(19) + '-';
+        result += '\n' + `${file}/${strDate + strSize}`;
+        continue;
+      }
+      let strSize = stats.size.toString();
+      strSize = ' '.repeat(20 - strSize.length) + strSize;
+
+      result += '\n' + `${file} ${strDate + strSize}`;
+    }
+
+    const resultHtmlEnd = `

`; + + return resultHtmlStart + result + resultHtmlEnd; + } +} diff --git a/src/app.module.ts b/src/app.module.ts index 464aa07..1900101 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,14 +1,5 @@ -import { - //MiddlewareConsumer, - Module, - //NestModule, - //RequestMethod, -} from '@nestjs/common'; +import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; -//import { AppService } from './app.service'; -//import { KodiApiController } from './KodiApi/kodi-api.controller'; -//import { StaticController } from './Static/static.controller'; -//import { KodiApiUrlRewriteMiddleware } from './KodiApi/UrlRewrite/url-rewrite.middleware'; import { KodiApiModule } from './KodiApi/kodi-api.module'; import { StaticModule } from './Static/static.module'; @@ -18,10 +9,3 @@ import { StaticModule } from './Static/static.module'; providers: [], }) export class AppModule {} -// export class AppModule implements NestModule { -// configure(consumer: MiddlewareConsumer) { -// consumer -// .apply(KodiApiUrlRewriteMiddleware) -// .forRoutes({ path: '/api*', method: RequestMethod.ALL }); -// } -// } diff --git a/tsconfig.json b/tsconfig.json index adb614c..6727ee5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,6 +16,7 @@ "noImplicitAny": false, "strictBindCallApply": false, "forceConsistentCasingInFileNames": false, - "noFallthroughCasesInSwitch": false + "noFallthroughCasesInSwitch": false, + "strict": true } }