Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,7 @@ KEYCLOAK_CLIENT_SECRET=
KEYCLOAK_BASE_URL=
KEYCLOAK_USERNAME=
KEYCLOAK_PASSWORD=

# Comma-separated file extensions (optional; defaults in config/files.php)
# ALLOWED_EXTENSIONS=pdf,doc,docx,txt,jpg,png
# DANGEROUS_EXTENSIONS=zip,rar,7z,tar
61 changes: 43 additions & 18 deletions config/files.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
<?php

$parseCommaSeparatedExtensions = static function (string $envKey, array $default): array {
$value = env($envKey);

if (!is_string($value) || trim($value) === '') {
return $default;
}

return array_values(array_filter(array_map(
static fn (string $extension) => strtolower(trim($extension)),
explode(',', $value)
)));
};

$defaultAllowedExtensions = [
// Documents
'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
'txt', 'csv',

// Images
'jpg', 'jpeg', 'png', 'gif', 'svg',

// Audio
'mp3',

// Video
'mp4', 'webm',
];

$defaultDangerousExtensions = [
'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'lzma',
'cab', 'ar', 'iso', 'dmg', 'pkg', 'deb', 'rpm',
];

return [
/*
|--------------------------------------------------------------------------
Expand All @@ -19,22 +52,13 @@
| List of file extensions that are allowed to be uploaded.
| Only files with these extensions will be accepted.
| Archive formats (.zip, .rar, .tar, .7z) are explicitly NOT allowed for security.
| Override with comma-separated ALLOWED_EXTENSIONS in .env (optional).
|
*/
'allowed_extensions' => [
// Documents
'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',
'txt', 'csv',

// Images
'jpg', 'jpeg', 'png', 'gif', 'svg',

// Audio
'mp3',

// Video
'mp4', 'webm',
],
'allowed_extensions' => $parseCommaSeparatedExtensions(
'ALLOWED_EXTENSIONS',
$defaultAllowedExtensions
),
Comment thread
henryjonathanquispe marked this conversation as resolved.
/*
|--------------------------------------------------------------------------
| Extension to MIME Type Mapping
Expand Down Expand Up @@ -116,12 +140,13 @@
| Archive formats (.zip, .rar, .tar, .7z, .gz, etc.) are explicitly
| NOT allowed for security reasons. These file types can contain
| malicious content and are blocked by default.
| Override with comma-separated DANGEROUS_EXTENSIONS in .env (optional).
|
*/
'dangerous_extensions' => [
'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'lzma',
'cab', 'ar', 'iso', 'dmg', 'pkg', 'deb', 'rpm',
],
'dangerous_extensions' => $parseCommaSeparatedExtensions(
'DANGEROUS_EXTENSIONS',
$defaultDangerousExtensions
),

/*
|--------------------------------------------------------------------------
Expand Down
85 changes: 85 additions & 0 deletions tests/unit/FilesConfigTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class FilesConfigTest extends TestCase
{
private const ENV_ALLOWED = 'ALLOWED_EXTENSIONS';

private const ENV_DANGEROUS = 'DANGEROUS_EXTENSIONS';

protected function setUp(): void
{
parent::setUp();

if (!function_exists('env')) {
require_once __DIR__ . '/../../vendor/laravel/framework/src/Illuminate/Foundation/helpers.php';
}
}

protected function tearDown(): void
{
$this->unsetEnv(self::ENV_ALLOWED);
$this->unsetEnv(self::ENV_DANGEROUS);

parent::tearDown();
}

public function test_allowed_extensions_use_defaults_when_env_unset(): void
{
$this->unsetEnv(self::ENV_ALLOWED);

$config = $this->loadFilesConfig();

$this->assertContains('pdf', $config['allowed_extensions']);
$this->assertContains('mp4', $config['allowed_extensions']);
}

public function test_allowed_extensions_parsed_from_env(): void
{
$this->setEnv(self::ENV_ALLOWED, 'pdf, custom ,TXT');

$config = $this->loadFilesConfig();

$this->assertSame(['pdf', 'custom', 'txt'], $config['allowed_extensions']);
}

public function test_dangerous_extensions_parsed_from_env(): void
{
$this->setEnv(self::ENV_DANGEROUS, 'zip,rar');

$config = $this->loadFilesConfig();

$this->assertSame(['zip', 'rar'], $config['dangerous_extensions']);
}

public function test_dangerous_extensions_defaults_when_env_empty(): void
{
$this->unsetEnv(self::ENV_DANGEROUS);

$config = $this->loadFilesConfig();

$this->assertContains('zip', $config['dangerous_extensions']);
$this->assertContains('7z', $config['dangerous_extensions']);
}

private function loadFilesConfig(): array
{
return include __DIR__ . '/../../config/files.php'; // NOSONAR: load fresh config after changing environment variables.
}

private function setEnv(string $key, string $value): void
{
putenv("{$key}={$value}");
$_ENV[$key] = $value;
$_SERVER[$key] = $value;
}

private function unsetEnv(string $key): void
{
putenv($key);
unset($_ENV[$key], $_SERVER[$key]);
}
}
Loading