Skip to content

Commit 5730f0e

Browse files
authored
Security fix (#44)
input validation --------- Signed-off-by: rahul <rcsofttech85@gmail.com>
1 parent ac88814 commit 5730f0e

File tree

10 files changed

+161
-43
lines changed

10 files changed

+161
-43
lines changed

bin/view-csv

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require 'vendor/autoload.php';
66
use Rcsofttech85\FileHandler\CsvFileHandler;
77
use Rcsofttech85\FileHandler\DependencyInjection\ServiceContainer;
88
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
9+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
910
use Symfony\Component\Console\Command\Command;
1011
use Symfony\Component\Console\Input\InputArgument;
1112
use Symfony\Component\Console\Input\InputInterface;
@@ -24,7 +25,11 @@ $command = (new SingleCommandApplication())
2425
$hiddenColumns = $input->getOption('hide-column');
2526
$limit = $input->getOption('limit');
2627

27-
if (!file_exists($csvFile)) {
28+
try {
29+
$csvFile = (new class {
30+
use FileValidatorTrait;
31+
})->validateFileName($csvFile);
32+
} catch (FileHandlerException) {
2833
$io->error("{$csvFile} does not exists");
2934
return Command::FAILURE;
3035
}

bin/view-json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Rcsofttech85\FileHandler\DependencyInjection\ServiceContainer;
55
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
66
use Rcsofttech85\FileHandler\JsonFileHandler;
7+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
78
use Symfony\Component\Console\Command\Command;
89
use Symfony\Component\Console\Input\InputArgument;
910
use Symfony\Component\Console\Input\InputInterface;
@@ -25,7 +26,11 @@ $command = (new SingleCommandApplication())
2526
$hiddenColumns = $input->getOption('hide-column');
2627
$hiddenColumns = $hiddenColumns ? explode(',', $hiddenColumns) : false;
2728

28-
if (!file_exists($jsonFile)) {
29+
try {
30+
$jsonFile = (new class {
31+
use FileValidatorTrait;
32+
})->validateFileName($jsonFile);
33+
} catch (FileHandlerException) {
2934
$io->error("{$jsonFile} does not exists");
3035
return Command::FAILURE;
3136
}

src/CsvFileHandler.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
use Generator;
66
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
77
use Rcsofttech85\FileHandler\Utilities\RowColumnHelper;
8+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
89

910
class CsvFileHandler
1011
{
1112
use RowColumnHelper;
13+
use FileValidatorTrait;
1214

1315
public function __construct(
1416
private readonly TempFileHandler $tempFileHandler
@@ -29,11 +31,6 @@ public function searchInCsvFile(
2931
string $column,
3032
string|null $format = null
3133
): bool|array {
32-
if (!file_exists($filename)) {
33-
throw new FileHandlerException('file not found');
34-
}
35-
36-
3734
foreach ($this->getRows($filename) as $row) {
3835
if ($keyword === $row[$column]) {
3936
return ($format === FileHandler::ARRAY_FORMAT) ? $row : true;
@@ -42,6 +39,11 @@ public function searchInCsvFile(
4239
return false;
4340
}
4441

42+
/**
43+
* @param string $filename
44+
* @return string|false
45+
* @throws FileHandlerException
46+
*/
4547

4648
public function toJson(string $filename): string|false
4749
{
@@ -53,18 +55,23 @@ public function toJson(string $filename): string|false
5355
/**
5456
* @param string $filename
5557
* @param array<string> $hideColumns
58+
* @param int|false $limit
5659
* @return array<int,array<string,string>>
5760
* @throws FileHandlerException
5861
*/
5962
public function toArray(string $filename, array|false $hideColumns = false, int|false $limit = false): array
6063
{
61-
if (!file_exists($filename)) {
62-
throw new FileHandlerException('file not found');
63-
}
64-
6564
return iterator_to_array($this->getRows($filename, $hideColumns, $limit));
6665
}
6766

67+
/**
68+
* @param string $filename
69+
* @param string $keyword
70+
* @param string $replace
71+
* @param string|null $column
72+
* @return bool
73+
* @throws FileHandlerException
74+
*/
6875
public function findAndReplaceInCsv(
6976
string $filename,
7077
string $keyword,
@@ -160,6 +167,7 @@ private function isValidCsvFileFormat(array $row): bool
160167
*/
161168
private function getRows(string $filename, array|false $hideColumns = false, int|false $limit = false): Generator
162169
{
170+
$filename = $this->validateFileName($filename);
163171
$csvFile = fopen($filename, 'r');
164172
if (!$csvFile) {
165173
throw new FileHandlerException('file not found');

src/DependencyInjection/ServiceContainer.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,22 @@
55
use Symfony\Component\Config\FileLocator;
66
use Symfony\Component\DependencyInjection\ContainerBuilder;
77
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
8+
use Symfony\Component\Dotenv\Dotenv;
89

910
class ServiceContainer
1011
{
1112
public function getContainerBuilder(): ContainerBuilder
1213
{
14+
$dotenv = new Dotenv();
15+
$dotenv->load('.env');
16+
17+
1318
$containerBuilder = new ContainerBuilder();
1419
$loader = new YamlFileLoader($containerBuilder, new FileLocator(__DIR__ . '/../../src/config'));
1520
$loader->load('services.yaml');
21+
22+
$containerBuilder->setParameter('FILE_NAME', $_ENV['FILE_NAME']);
23+
1624
return $containerBuilder;
1725
}
1826
}

src/FileEncryptor.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,26 @@
44

55
use Exception;
66
use Rcsofttech85\FileHandler\Exception\FileEncryptorException;
7+
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
8+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
79
use SensitiveParameter;
810
use SodiumException;
911

1012
readonly class FileEncryptor
1113
{
14+
use FileValidatorTrait;
15+
16+
/**
17+
* @param string $filename
18+
* @param string $secret
19+
*
20+
* @throws FileHandlerException
21+
*/
1222
public function __construct(
1323
private string $filename,
1424
#[SensitiveParameter] private string $secret
1525
) {
16-
if (!file_exists($this->filename)) {
17-
throw new FileEncryptorException("File not found");
18-
}
26+
$this->validateFileName($filename);
1927
}
2028

2129
/**

src/FileHandler.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
use finfo;
66
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
7+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
78
use ZipArchive;
89

910
class FileHandler
1011
{
12+
use FileValidatorTrait;
13+
1114
public const ARRAY_FORMAT = 'array';
1215

1316
/**
@@ -16,12 +19,16 @@ class FileHandler
1619
private null|array $files = [];
1720

1821

22+
/**
23+
* @throws FileHandlerException
24+
*/
1925
public function open(
2026
string $filename,
2127
string $mode = "w",
2228
bool $include_path = false,
2329
mixed $context = null
2430
): self {
31+
$filename = $this->sanitize($filename);
2532
$file = fopen($filename, $mode, $include_path, $context);
2633

2734
if (!$file) {
@@ -58,9 +65,7 @@ public function write(string $data, ?int $length = null): void
5865
*/
5966
public function compress(string $filename, string $zipFilename): void
6067
{
61-
if (!file_exists($filename)) {
62-
throw new FileHandlerException('File to compress does not exist.');
63-
}
68+
$filename = $this->validateFileName($filename);
6469

6570
$zip = new ZipArchive();
6671

@@ -81,9 +86,7 @@ public function compress(string $filename, string $zipFilename): void
8186
*/
8287
public function getMimeType(string $filename): string
8388
{
84-
if (!file_exists($filename)) {
85-
throw new FileHandlerException('file does not exist.');
86-
}
89+
$filename = $this->validateFileName($filename);
8790

8891
$fileInfo = new finfo(FILEINFO_MIME_TYPE);
8992
$mimeType = $fileInfo->file($filename);
@@ -99,9 +102,7 @@ public function getMimeType(string $filename): string
99102
*/
100103
public function decompress(string $zipFilename, string $extractPath = "./"): void
101104
{
102-
if (!file_exists($zipFilename)) {
103-
throw new FileHandlerException('ZIP archive does not exist.');
104-
}
105+
$zipFilename = $this->validateFileName($zipFilename);
105106

106107
$zip = new ZipArchive();
107108

@@ -142,9 +143,8 @@ public function resetFiles(): void
142143
*/
143144
public function delete(string $filename): void
144145
{
145-
if (!file_exists($filename)) {
146-
throw new FileHandlerException('file does not exists');
147-
}
146+
$filename = $this->validateFileName($filename);
147+
148148
unlink($filename);
149149
}
150150
}

src/FileHashChecker.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,23 @@
33
namespace Rcsofttech85\FileHandler;
44

55
use Rcsofttech85\FileHandler\Exception\HashException;
6+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
67

78
class FileHashChecker
89
{
10+
use FileValidatorTrait;
11+
912
public const ALGO_256 = 'sha3-256';
1013
public const ALGO_512 = 'sha3-512';
1114

1215
/**
1316
* @param string $filename
1417
* @param CsvFileHandler $csvFileHandler
15-
* @throws HashException
18+
* @throws Exception\FileHandlerException
1619
*/
17-
public function __construct(private readonly string $filename, private readonly CsvFileHandler $csvFileHandler)
20+
public function __construct(private string $filename, private readonly CsvFileHandler $csvFileHandler)
1821
{
19-
if (!file_exists($this->filename)) {
20-
throw new HashException('file not found');
21-
}
22+
$this->filename = $this->validateFileName($filename);
2223
}
2324

2425
/**

src/JsonFileHandler.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
use Generator;
66
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
77
use Rcsofttech85\FileHandler\Utilities\RowColumnHelper;
8+
use Rcsofttech85\FileHandler\Validator\FileValidatorTrait;
89

910
class JsonFileHandler
1011
{
1112
use RowColumnHelper;
13+
use FileValidatorTrait;
1214

1315
/**
1416
* @param string $filename
@@ -35,7 +37,7 @@ public function toArray(
3537

3638
private function validateFile(string $filename): array
3739
{
38-
$this->checkFileExistence($filename);
40+
$filename = $this->validateFileName($filename);
3941
$jsonContents = $this->getFileContents($filename);
4042
$contents = $this->parseJson($jsonContents);
4143
if (!$contents) {
@@ -45,17 +47,6 @@ private function validateFile(string $filename): array
4547
return $contents;
4648
}
4749

48-
/**
49-
* @param string $filename
50-
* @return void
51-
* @throws FileHandlerException
52-
*/
53-
private function checkFileExistence(string $filename): void
54-
{
55-
if (!file_exists($filename)) {
56-
throw new FileHandlerException('File not found');
57-
}
58-
}
5950

6051
/**
6152
* @param string $filename
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Rcsofttech85\FileHandler\Validator;
4+
5+
use Rcsofttech85\FileHandler\DependencyInjection\ServiceContainer;
6+
use Rcsofttech85\FileHandler\Exception\FileHandlerException;
7+
8+
trait FileValidatorTrait
9+
{
10+
/**
11+
* @param string $filename
12+
* @param string|null $path
13+
* @return string
14+
* @throws FileHandlerException
15+
*/
16+
public function validateFileName(string $filename, string|null $path = null): string
17+
{
18+
$container = (new ServiceContainer())->getContainerBuilder();
19+
20+
$stored_hash_file = $container->getParameter('FILE_NAME');
21+
22+
if ($filename != $stored_hash_file) {
23+
self::sanitize($filename);
24+
}
25+
26+
27+
if ($path) {
28+
$absolutePath = realpath($path);
29+
$absolutePath ?:
30+
throw new FileHandlerException("path {$path} is not valid')");
31+
$filename = $absolutePath . DIRECTORY_SEPARATOR . $filename;
32+
}
33+
34+
35+
if (!file_exists($filename)) {
36+
throw new FileHandlerException('file not found');
37+
}
38+
return $filename;
39+
}
40+
41+
/**
42+
* @throws FileHandlerException
43+
*/
44+
public function sanitize(string $filename): string
45+
{
46+
$pattern = '/^[a-zA-Z0-9_.-]+$/';
47+
if (!preg_match($pattern, $filename)) {
48+
throw new FileHandlerException('file not found');
49+
}
50+
51+
return $filename;
52+
}
53+
}

0 commit comments

Comments
 (0)