Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public function index($id, $pattern)
$volume = Volume::findOrFail($id);
$this->authorize('access', $volume);

// Decode percent-encoded characters, example:
// Frontend turns / into %2F, we turn it back to /
$pattern = rawurldecode($pattern);

// Escape trailing backslashes, else there would be an error with ilike.
$pattern = preg_replace('/\\\\$/', '\\\\\\\\', $pattern);

Expand Down
2 changes: 1 addition & 1 deletion resources/assets/js/volumes/cloneForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export default {
let promise1 = VolumeApi.queryFilenames({id: this.id});
let promise2 = VolumeApi.queryFilesWithFilename({
id: this.id,
pattern: this.filePattern
pattern: encodeURIComponent(this.filePattern)
Comment thread
yannik131 marked this conversation as resolved.
Outdated
});

Promise.all([promise1, promise2])
Expand Down
2 changes: 1 addition & 1 deletion resources/assets/js/volumes/stores/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ let filenameFilter = {
getSequence(volumeId, pattern) {
return VolumesApi.queryFilesWithFilename({
id: volumeId,
pattern: pattern,
pattern: encodeURIComponent(pattern),
});
},
Comment thread
yannik131 marked this conversation as resolved.
};
Expand Down
2 changes: 1 addition & 1 deletion routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@

$router->get('{id}/files/filter/filename/{pattern}', [
'uses' => 'Filters\FilenameController@index',
]);
])->where('pattern', '.*');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this if it matches anything?

Copy link
Copy Markdown
Contributor Author

@yannik131 yannik131 May 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After additional investigation:

  • Laravel already encodes/decodes URI components
  • However, laravel decodes the route parameters and throws an exception if the decoded pattern contains invalid characters such as slashes
  • 2 possible fixes:
    • encode/decode manually on top of vue/laravel encoding/decoding, then laravel can't "see" the invalid characters after decoding the pattern just once
    • add the ->where('pattern', '.*'); to explicitly allow any characters, including slashes

The second approach is actually cleaner so I'll remove the manual encoding/decoding

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment here why this is used, then. And you think we shouldn't use encodeURIComponent in JS as well? Is seems a safer bet.


$router->get('{id}/file-labels', [
'uses' => 'UsedFileLabelsController@index',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,32 @@ public function testIndexEscape()
{
$vid = $this->volume()->id;

$image = ImageTest::create([
$image1 = ImageTest::create([
'volume_id' => $vid,
'filename' => 'abcde.jpg',
]);
$image2 = ImageTest::create([
'volume_id' => $vid,
'filename' => '/.jpg'
]);
$image3 = ImageTest::create([
'volume_id' => $vid,
'filename' => '%2F.jpg' // encodeURIComponent("/") yields "%2F"
Comment thread
yannik131 marked this conversation as resolved.
Outdated
Comment thread
yannik131 marked this conversation as resolved.
Outdated
]);

$expectedResults = [
'*cde*%5C' => [],
'%2F.jpg' => [$image2->id], // "/.jpg"
'%2F*' => [$image2->id], // "/*"
'%25252F.jpg' => [$image3->id], // "%2F.jpg"
];

$this->beGuest();
$response = $this->json('GET', "/api/v1/volumes/{$vid}/files/filter/filename/*cde*%5C")
->assertExactJson([]);
$response->assertStatus(200);
foreach ($expectedResults as $pattern => $expectedIds) {
$response = $this->json('GET', "/api/v1/volumes/{$vid}/files/filter/filename/{$pattern}")
->assertExactJson($expectedIds);
$response->assertStatus(200);
}
}

public function testIndexVideo()
Expand Down