Fix for UTF8 filename issues (#12)

This commit is contained in:
Milos Stojanovic
2019-09-05 13:59:20 +02:00
parent 3182ed058a
commit 2ea77cc88e
7 changed files with 69 additions and 13 deletions

View File

@@ -43,10 +43,10 @@ class DownloadController
$this->storage->setPathPrefix($user->getHomeDir()); $this->storage->setPathPrefix($user->getHomeDir());
} }
public function download($path_encoded, Request $request, Response $response, StreamedResponse $streamedResponse) public function download(Request $request, Response $response, StreamedResponse $streamedResponse)
{ {
try { try {
$file = $this->storage->readStream((string) base64_decode($path_encoded)); $file = $this->storage->readStream((string) base64_decode($request->input('path')));
} catch (\Exception $e) { } catch (\Exception $e) {
return $response->redirect('/'); return $response->redirect('/');
} }
@@ -67,7 +67,7 @@ class DownloadController
$streamedResponse->headers->set( $streamedResponse->headers->set(
'Content-Disposition', 'Content-Disposition',
HeaderUtils::makeDisposition(HeaderUtils::DISPOSITION_ATTACHMENT, $file['filename']) HeaderUtils::makeDisposition(HeaderUtils::DISPOSITION_ATTACHMENT, $file['filename'], 'file')
); );
$streamedResponse->headers->set( $streamedResponse->headers->set(
'Content-Type', 'Content-Type',
@@ -131,7 +131,8 @@ class DownloadController
'Content-Disposition', 'Content-Disposition',
HeaderUtils::makeDisposition( HeaderUtils::makeDisposition(
HeaderUtils::DISPOSITION_ATTACHMENT, HeaderUtils::DISPOSITION_ATTACHMENT,
$this->config->get('frontend_config.default_archive_name') $this->config->get('frontend_config.default_archive_name'),
'archive.zip'
) )
); );
$streamedResponse->headers->set( $streamedResponse->headers->set(

View File

@@ -184,7 +184,7 @@ return [
], ],
[ [
'route' => [ 'route' => [
'GET', '/download/{path_encoded}', '\Filegator\Controllers\DownloadController@download', 'GET', '/download', '\Filegator\Controllers\DownloadController@download',
], ],
'roles' => [ 'roles' => [
'guest', 'user', 'admin', 'guest', 'user', 'admin',

View File

@@ -155,6 +155,7 @@ import Pagination from './partials/Pagination'
import Upload from './partials/Upload' import Upload from './partials/Upload'
import api from '../api/api' import api from '../api/api'
import VueClipboard from 'vue-clipboard2' import VueClipboard from 'vue-clipboard2'
import { Base64 } from 'js-base64'
import _ from 'lodash' import _ from 'lodash'
Vue.use(VueClipboard) Vue.use(VueClipboard)
@@ -335,7 +336,7 @@ export default {
}) })
}, },
getDownloadLink(item) { getDownloadLink(item) {
return Vue.config.baseURL+'/download/'+btoa(item.path) return Vue.config.baseURL+'/download&path='+encodeURIComponent(Base64.encode(item.path))
}, },
download(item) { download(item) {
window.open(this.getDownloadLink(item), '_blank') window.open(this.getDownloadLink(item), '_blank')

3
package-lock.json generated
View File

@@ -11200,8 +11200,7 @@
"js-base64": { "js-base64": {
"version": "2.5.1", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
"integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw=="
"dev": true
}, },
"js-beautify": { "js-beautify": {
"version": "1.10.0", "version": "1.10.0",

View File

@@ -35,5 +35,7 @@
"vue-template-compiler": "^2.5.21", "vue-template-compiler": "^2.5.21",
"vuex": "^3.1.1" "vuex": "^3.1.1"
}, },
"dependencies": {} "dependencies": {
"js-base64": "^2.5.1"
}
} }

View File

@@ -156,7 +156,21 @@ class FilesTest extends TestCase
touch(TEST_REPOSITORY.'/john/john.txt', $this->timestamp); touch(TEST_REPOSITORY.'/john/john.txt', $this->timestamp);
$path_encoded = base64_encode('john.txt'); $path_encoded = base64_encode('john.txt');
$this->sendRequest('GET', '/download/'.$path_encoded); $this->sendRequest('GET', '/download&path='.$path_encoded);
$this->assertOk();
}
public function testDownloadUTF8File()
{
$username = 'john@example.com';
$this->signIn($username, 'john123');
mkdir(TEST_REPOSITORY.'/john');
touch(TEST_REPOSITORY.'/john/ąčęėįšųū.txt', $this->timestamp);
$path_encoded = base64_encode('/ąčęėįšųū.txt');
$this->sendRequest('GET', '/download&path='.$path_encoded);
$this->assertOk(); $this->assertOk();
} }
@@ -166,7 +180,7 @@ class FilesTest extends TestCase
touch(TEST_REPOSITORY.'/test.txt', $this->timestamp); touch(TEST_REPOSITORY.'/test.txt', $this->timestamp);
$path_encoded = base64_encode('test.txt'); $path_encoded = base64_encode('test.txt');
$this->sendRequest('GET', '/download/'.$path_encoded); $this->sendRequest('GET', '/download&path='.$path_encoded);
$this->assertStatus(404); $this->assertStatus(404);
} }
@@ -181,7 +195,7 @@ class FilesTest extends TestCase
touch(TEST_REPOSITORY.'/jane/jane.txt', $this->timestamp); touch(TEST_REPOSITORY.'/jane/jane.txt', $this->timestamp);
$path_encoded = base64_encode('jane.txt'); $path_encoded = base64_encode('jane.txt');
$this->sendRequest('GET', '/download/'.$path_encoded); $this->sendRequest('GET', '/download&path='.$path_encoded);
$this->assertStatus(404); $this->assertStatus(404);
} }
@@ -192,7 +206,7 @@ class FilesTest extends TestCase
$this->signIn($username, 'john123'); $this->signIn($username, 'john123');
$path_encoded = base64_encode('missing.txt'); $path_encoded = base64_encode('missing.txt');
$this->sendRequest('GET', '/download/'.$path_encoded); $this->sendRequest('GET', '/download&path='.$path_encoded);
$this->assertStatus(302); $this->assertStatus(302);
} }

View File

@@ -317,4 +317,43 @@ class UploadTest extends TestCase
], ],
]); ]);
} }
public function testFileUploadWithUTF8()
{
$this->signIn('john@example.com', 'john123');
$files = ['file' => new UploadedFile(TEST_FILE, 'ąčęėįšųū.txt', 'text/plain', null, true)];
$data = [
'resumableChunkNumber' => 1,
'resumableChunkSize' => 1048576,
'resumableCurrentChunkSize' => 0.5 * 1024 * 1024,
'resumableTotalChunks' => 1,
'resumableTotalSize' => 0.5 * 1024 * 1024,
'resumableType' => 'text/plain',
'resumableIdentifier' => 'CHUNKS-SIMPLE-TEST',
'resumableFilename' => "ąčęėįšųū.txt",
'resumableRelativePath' => '/',
];
$this->sendRequest('POST', '/upload', $data, $files);
$this->assertOk();
$this->sendRequest('POST', '/getdir', [
'dir' => '/',
]);
$this->assertResponseJsonHas([
'data' => [
'files' => [
0 => [
'type' => 'file',
'path' => '/ąčęėįšųū.txt',
'name' => 'ąčęėįšųū.txt',
],
],
],
]);
}
} }