Skip to content

Commit

Permalink
fix: make sure we process mime extensions as string
Browse files Browse the repository at this point in the history
Signed-off-by: skjnldsv <[email protected]>
  • Loading branch information
skjnldsv committed Feb 5, 2025
1 parent 83e35b6 commit 3061c5d
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class GenerateMimetypeFileBuilder {
public function generateFile(array $aliases): string {
// Remove comments
$aliases = array_filter($aliases, static function ($key) {
// Single digit extensions will be treated as integers
// Let's make sure they are strings
// https://github.com/nextcloud/server/issues/42902
$key = (string)$key;
return !($key === '' || $key[0] === '_');
}, ARRAY_FILTER_USE_KEY);

Expand Down
4 changes: 4 additions & 0 deletions core/Command/Maintenance/Mimetype/UpdateDB.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$totalNewMimetypes = 0;

foreach ($mappings as $ext => $mimetypes) {
// Single digit extensions will be treated as integers
// Let's make sure they are strings
// https://github.com/nextcloud/server/issues/42902
$ext = (string)$ext;
if ($ext[0] === '_') {
// comment
continue;
Expand Down
17 changes: 12 additions & 5 deletions lib/private/Files/Type/Detection.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Detection implements IMimeTypeDetector {
private const CUSTOM_MIMETYPEMAPPING = 'mimetypemapping.json';
private const CUSTOM_MIMETYPEALIASES = 'mimetypealiases.json';

/** @var array<string, array{string, string|null}> */
protected array $mimetypes = [];
protected array $secureMimeTypes = [];

Expand Down Expand Up @@ -52,7 +53,9 @@ public function __construct(
public function registerType(string $extension,
string $mimetype,
?string $secureMimeType = null): void {
$this->mimetypes[$extension] = [$mimetype, $secureMimeType];
// Make sure the extension is a string
// https://github.com/nextcloud/server/issues/42902
$this->mimetypes[(string)$extension] = [$mimetype, $secureMimeType];

Check failure on line 58 in lib/private/Files/Type/Detection.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

RedundantCast

lib/private/Files/Type/Detection.php:58:20: RedundantCast: Redundant cast to string (see https://psalm.dev/262)
$this->secureMimeTypes[$mimetype] = $secureMimeType ?: $mimetype;
}

Expand All @@ -66,13 +69,17 @@ public function registerType(string $extension,
* @param array $types
*/
public function registerTypeArray(array $types): void {
$this->mimetypes = array_merge($this->mimetypes, $types);
// Register the types,
foreach ($types as $extension => $mimeType) {
$this->registerType((string)$extension, $mimeType[0], $mimeType[1] ?? null);
}

// Update the alternative mimetypes to avoid having to look them up each time.
foreach ($this->mimetypes as $extension => $mimeType) {
if (str_starts_with($extension, '_comment')) {
if (str_starts_with((string)$extension, '_comment')) {
continue;
}

$this->secureMimeTypes[$mimeType[0]] = $mimeType[1] ?? $mimeType[0];
if (isset($mimeType[1])) {
$this->secureMimeTypes[$mimeType[1]] = $mimeType[1];
Expand Down Expand Up @@ -133,7 +140,7 @@ private function loadMappings(): void {
}

/**
* @return array
* @return array<string, array{string, string|null}>

Check failure on line 143 in lib/private/Files/Type/Detection.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

ImplementedReturnTypeMismatch

lib/private/Files/Type/Detection.php:143:13: ImplementedReturnTypeMismatch: The inherited return type 'array<string, string>' for OCP\Files\IMimeTypeDetector::getAllMappings is different to the implemented return type for OC\Files\Type\Detection::getallmappings 'array<string, list{string, null|string}>' (see https://psalm.dev/123)
*/
public function getAllMappings(): array {
$this->loadMappings();
Expand Down Expand Up @@ -163,7 +170,7 @@ public function detectPath($path): string {
$extension = strrchr($fileName, '.');
if ($extension !== false) {
$extension = strtolower($extension);
$extension = substr($extension, 1); //remove leading .
$extension = substr($extension, 1); // remove leading .
return $this->mimetypes[$extension][0] ?? 'application/octet-stream';
}
}
Expand Down
6 changes: 6 additions & 0 deletions lib/public/Files/IMimeTypeDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,10 @@ public function mimeTypeIcon($mimeType);
* @since 28.0.0
*/
public function getAllAliases(): array;

/**
* @return array<string,string>
* @since 8.2.0
*/
public function getAllMappings(): array;
}
10 changes: 10 additions & 0 deletions lib/public/Files/IMimeTypeLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,14 @@ public function exists(string $mimetype): bool;
* @since 8.2.0
*/
public function reset(): void;

/**
* Update filecache mimetype based on file extension
*
* @param string $ext
* @param int $mimeTypeId
* @return int
* @since 8.2.0
*/
public function updateFilecache(string $ext, int $mimeTypeId): int;
}
35 changes: 35 additions & 0 deletions tests/lib/Files/Type/DetectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,41 @@ public function testDetectString(): void {
$this->assertEquals($expected, $result);
}

public function dataMimeTypeCustom(): array {
return [
['123', 'foobar/123'],
['a123', 'foobar/123'],
['bar', 'foobar/bar'],
];
}

/**
* @dataProvider dataMimeTypeCustom
*
* @param string $ext
* @param string $mime
*/
public function testDetectMimeTypeCustom(string $ext, string $mime): void {
$confDir = sys_get_temp_dir();
file_put_contents($confDir . '/mimetypemapping.dist.json', json_encode([]));

/** @var IURLGenerator $urlGenerator */
$urlGenerator = $this->getMockBuilder(IURLGenerator::class)
->disableOriginalConstructor()
->getMock();

/** @var LoggerInterface $logger */
$logger = $this->createMock(LoggerInterface::class);

// Create new mapping file
file_put_contents($confDir . '/mimetypemapping.dist.json', json_encode([$ext => [$mime]]));

$detection = new Detection($urlGenerator, $logger, $confDir, $confDir);
$mappings = $detection->getAllMappings();
$this->assertArrayHasKey($ext, $mappings);
$this->assertEquals($mime, $detection->detectPath('foo.' . $ext));
}

public function dataGetSecureMimeType(): array {
return [
['image/svg+xml', 'text/plain'],
Expand Down

0 comments on commit 3061c5d

Please sign in to comment.