Skip to content

Commit

Permalink
invalid file name index
Browse files Browse the repository at this point in the history
  • Loading branch information
Alfagun74 committed Dec 11, 2023
1 parent 2d64044 commit d3b4ad4
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 6 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@ Recommended Gamevault App Version: `v1.8.0`

- `SERVER_REGISTRATION_DISABLED` won't block registration calls by administrators anymore. [#221](https://github.com/Phalcode/gamevault-backend/issues/221)

- Fixed initial folder generation not happening

- Fixed Server indexing games with invalid filenames. [#281](https://github.com/Phalcode/gamevault-app/issues/281)

### Thanks

- @RIPSAW
- @utlilb
- @JoaGamo

## 9.0.5

Expand Down
111 changes: 111 additions & 0 deletions src/modules/files/files.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
https://docs.nestjs.com/fundamentals/testing#unit-testing
*/

import { Test } from "@nestjs/testing";
import { FilesService } from "./files.service";
import { GamesService } from "../games/games.service";
import { RawgService } from "../providers/rawg/rawg.service";
import { BoxArtsService } from "../boxarts/boxarts.service";

describe("FilesService", () => {
let filesService: FilesService;

const mockGamesService = {};
const mockRawgService = {};
const mockBoxartService = {};

beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
providers: [FilesService, GamesService, RawgService, BoxArtsService],
})
.overrideProvider(GamesService)
.useValue(mockGamesService)
.overrideProvider(RawgService)
.useValue(mockRawgService)
.overrideProvider(BoxArtsService)
.useValue(mockBoxartService)
.compile();

filesService = moduleRef.get<FilesService>(FilesService);
});

it("should be defined", () => {
expect(filesService).toBeDefined();
});

describe("isValidFilename", () => {
let loggerDebugSpy, loggerWarnSpy;

beforeEach(() => {
// Create spies for logger.debug and logger.warn methods
loggerDebugSpy = jest
.spyOn(filesService["logger"], "debug")
.mockImplementation((text) => {
console.log(text);
});
loggerWarnSpy = jest
.spyOn(filesService["logger"], "warn")
.mockImplementation((text) => {
console.warn(text);
});
});

afterEach(() => {
// Restore the original logger.debug and logger.warn methods
loggerDebugSpy.mockRestore();
loggerWarnSpy.mockRestore();
});

it("should return false for unsupported file extensions", () => {
const unsupportedFilenames = [
"Assassin's Creed Odyssey (v1.5.3) (2018).pig",
"Red Dead Redemption 2 (v1.2) (2020).rat",
"Cyberpunk 2077 (v1.3.1) (2021).giraffe",
];

unsupportedFilenames.forEach((filename) => {
expect(filesService["isValidFilename"](filename)).toBe(false);
expect(loggerDebugSpy).toHaveBeenCalledWith(
`Indexer ignoring invalid filename: unsupported file extension - ${filename}`,
);
});
});

it("should return false for filenames with invalid characters", () => {
const invalidFilenames = [
"DOOM: Eternal (v2.1) (2020).zip",
"The Legend of Zelda: Breath of the Wild (v1.2) (2017).7z",
"Dishonored <2> (v1.11) (2016).tar",
];

invalidFilenames.forEach((filename) => {
expect(filesService["isValidFilename"](filename)).toBe(false);
expect(loggerWarnSpy).toHaveBeenCalledWith(
`Indexer ignoring invalid filename: contains invalid characters - ${filename}`,
);
});
});

it("should return true for valid filenames", () => {
const validFilenames = [
"Star Wars Jedi - Fallen Order (v1.0.10.0) (2019).zip",
"HITMAN 3 (v3.10.1) (2021).7z",
"The Wandering Village (v0.1.32) (EA) (2022).iso",
"Saints Row (W_S) (2022).zip",
"My personal IndieGame (v1.2.9) (NC) (2018).zip",
"Stray (2022).7z",
"Captain of Industry (v0.4.12b) (EA) (2022).gz",
"Minecraft (2011).exe",
];

validFilenames.forEach((filename) => {
expect(filesService["isValidFilename"](filename)).toBe(true);
});

// Ensure logger.debug and logger.warn were not called for valid filenames
expect(loggerDebugSpy).not.toHaveBeenCalled();
expect(loggerWarnSpy).not.toHaveBeenCalled();
});
});
});
33 changes: 27 additions & 6 deletions src/modules/files/files.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { debounce } from "lodash";

@Injectable()
export class FilesService implements OnApplicationBootstrap {
private readonly logger = new Logger(FilesService.name);
private logger = new Logger(FilesService.name);

constructor(
private gamesService: GamesService,
Expand All @@ -44,6 +44,7 @@ export class FilesService implements OnApplicationBootstrap {
) {}

onApplicationBootstrap() {
this.checkFolders();
watch(configuration.VOLUMES.FILES, {
depth: configuration.GAMES.SEARCH_RECURSIVE ? undefined : 0,
})
Expand Down Expand Up @@ -154,6 +155,30 @@ export class FilesService implements OnApplicationBootstrap {
return this.gamesService.save(updatedGame);
}

private isValidFilename(filename: string) {
const invalidCharacters = /[\/<>:"\\|?*]/;

if (
!configuration.GAMES.SUPPORTED_FILE_FORMATS.includes(
extname(filename).toLowerCase(),
)
) {
this.logger.debug(
`Indexer ignoring invalid filename: unsupported file extension - ${filename}`,
);
return false;
}

if (invalidCharacters.test(filename)) {
this.logger.warn(
`Indexer ignoring invalid filename: contains invalid characters - ${filename}`,
);
return false;
}

return true;
}

/**
* This method extracts the game title from a given file name string using a
* regular expression.
Expand Down Expand Up @@ -421,11 +446,7 @@ export class FilesService implements OnApplicationBootstrap {
encoding: "utf8",
recursive: configuration.GAMES.SEARCH_RECURSIVE,
})
.filter((file) =>
configuration.GAMES.SUPPORTED_FILE_FORMATS.includes(
extname(file).toLowerCase(),
),
)
.filter((file) => this.isValidFilename(file))
.map(
(file) =>
({
Expand Down

0 comments on commit d3b4ad4

Please sign in to comment.