├── .env.local ├── .env.production ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ ├── nodejs.yml │ └── php.yml ├── .gitignore ├── .php_cs ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── backend ├── App.php ├── Config │ └── Config.php ├── Container │ ├── Container.php │ └── ContainerInterface.php ├── Controllers │ ├── AdminController.php │ ├── AuthController.php │ ├── DownloadController.php │ ├── ErrorController.php │ ├── FileController.php │ ├── UploadController.php │ └── ViewController.php ├── Kernel │ ├── Request.php │ ├── Response.php │ └── StreamedResponse.php ├── Services │ ├── Archiver │ │ ├── Adapters │ │ │ └── ZipArchiver.php │ │ └── ArchiverInterface.php │ ├── Auth │ │ ├── Adapters │ │ │ ├── Database.php │ │ │ ├── JsonFile.php │ │ │ ├── LDAP.php │ │ │ └── WPAuth.php │ │ ├── AuthInterface.php │ │ ├── User.php │ │ └── UsersCollection.php │ ├── Cors │ │ └── Cors.php │ ├── Logger │ │ ├── Adapters │ │ │ └── MonoLogger.php │ │ └── LoggerInterface.php │ ├── Process │ │ └── SymfonyProcessFactory.php │ ├── Router │ │ └── Router.php │ ├── Security │ │ └── Security.php │ ├── Service.php │ ├── ServiceFactory.php │ ├── Session │ │ ├── Adapters │ │ │ └── SessionStorage.php │ │ ├── Session.php │ │ └── SessionStorageInterface.php │ ├── Storage │ │ ├── DirectoryCollection.php │ │ └── Filesystem.php │ ├── Tmpfs │ │ ├── Adapters │ │ │ └── Tmpfs.php │ │ └── TmpfsInterface.php │ └── View │ │ ├── Adapters │ │ └── Vuejs.php │ │ └── ViewInterface.php └── Utils │ ├── Collection.php │ └── PasswordHash.php ├── composer.74.json ├── composer.json ├── composer.lock ├── config ├── routes.config.php ├── routes.optional.config.php └── services.config.php ├── configuration_sample.php ├── couscous.yml ├── cypress.json ├── data └── filebrowser_package_create.bash ├── dist ├── favicon.ico ├── fonts │ ├── fa-brands-400.eot │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.eot │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ └── fa-solid-900.woff2 ├── img │ ├── fa-brands-400.svg │ ├── fa-regular-400.svg │ ├── fa-solid-900.svg │ └── logo.png ├── index.php ├── manifest.json ├── robots.txt └── service-worker.js ├── docs ├── Makefile ├── accounts.rst ├── conf.py ├── configuration │ ├── auth.rst │ ├── logging.rst │ ├── router.rst │ ├── security.rst │ ├── sessions.rst │ ├── storage.rst │ └── tmpfs.rst ├── configuration_basic.rst ├── development.rst ├── images │ └── logo.png ├── index.rst ├── installation.rst ├── introduction.rst ├── license.rst ├── make.bat ├── requirements.txt └── translations │ └── default.rst ├── frontend ├── App.vue ├── api │ └── api.js ├── assets │ └── logo.png ├── main.js ├── mixins │ └── shared.js ├── registerServiceWorker.js ├── router.js ├── store.js ├── translations │ ├── bulgarian.js │ ├── chinese.js │ ├── czech.js │ ├── dutch.js │ ├── english.js │ ├── french.js │ ├── galician.js │ ├── german.js │ ├── hungarian.js │ ├── indonesian.js │ ├── italian.js │ ├── japanese.js │ ├── korean.js │ ├── lithuanian.js │ ├── polish.js │ ├── portuguese.js │ ├── russian.js │ ├── serbian.js │ ├── slovak.js │ ├── spanish.js │ ├── swedish.js │ └── turkish.js └── views │ ├── Browser.vue │ ├── Login.vue │ ├── Users.vue │ └── partials │ ├── Editor.vue │ ├── Gallery.vue │ ├── Menu.vue │ ├── Pagination.vue │ ├── Profile.vue │ ├── Search.vue │ ├── Tree.vue │ ├── TreeNode.vue │ ├── Upload.vue │ └── UserEdit.vue ├── index.php ├── jest.config.js ├── linuxforcomposer.json ├── package-lock.json ├── package.json ├── phpunit.xml ├── postcss.config.js ├── private ├── .gitignore ├── .htaccess ├── logs │ └── .gitignore ├── sessions │ └── .gitignore └── users.json.blank ├── repository └── .gitignore ├── robots.txt ├── tests ├── backend │ ├── FakeResponse.php │ ├── FakeStreamedResponse.php │ ├── Feature │ │ ├── AdminTest.php │ │ ├── AppTest.php │ │ ├── AuthTest.php │ │ ├── FeatureTest.php │ │ ├── FilesFastzipTest.php │ │ ├── FilesTest.php │ │ └── UploadTest.php │ ├── MockUsers.php │ ├── TestCase.php │ ├── TestResponse.php │ ├── Unit │ │ ├── ArchiverTest.php │ │ ├── Auth │ │ │ ├── AuthTest.php │ │ │ ├── DatabaseAuthTest.php │ │ │ └── JsonAuthTest.php │ │ ├── CollectionTest.php │ │ ├── ConfigTest.php │ │ ├── FilesystemTest.php │ │ ├── MainTest.php │ │ ├── RequestTest.php │ │ ├── RouterTest.php │ │ ├── SessionStorageTest.php │ │ ├── SymfonyProcessFactoryTest.php │ │ ├── TmpfsTest.php │ │ ├── UserTest.php │ │ └── ViewTest.php │ ├── configuration.fastzip.php │ ├── configuration.php │ └── tmp │ │ ├── .gitignore │ │ └── testarchive.zip ├── config │ ├── testroutes.php │ └── testroutesoptional.php └── frontend │ ├── .browserslistrc │ ├── .eslintrc.js │ ├── .gitignore │ ├── e2e │ ├── .eslintrc.js │ ├── fixtures │ │ ├── dir_home.json │ │ ├── dir_mydocs.json │ │ ├── getconfig.json │ │ ├── getuser.json │ │ ├── listusers.json │ │ ├── login_admin.json │ │ └── login_user.json │ ├── plugins │ │ └── index.js │ ├── specs │ │ └── test.js │ └── support │ │ ├── commands.js │ │ └── index.js │ └── unit │ ├── .eslintrc.js │ └── example.spec.js └── vue.config.js /.env.local: -------------------------------------------------------------------------------- 1 | VUE_APP_API_ENDPOINT='http://localhost:8181/?r=' 2 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | VUE_APP_API_ENDPOINT= 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | // add more generic rulesets here, such as: 4 | 'eslint:recommended', 5 | 'plugin:vue/recommended', 6 | ], 7 | rules: { 8 | // override/add rules settings here, such as: 9 | 'no-console': 0, 10 | 'no-unused-vars': 'error', 11 | 'vue/require-prop-types': 0, 12 | 'vue/max-attributes-per-line': 4, 13 | 'vue/attributes-order': 0, 14 | 'semi': [ 15 | 'error', 16 | 'never' 17 | ], 18 | 'linebreak-style': [ 19 | 'error', 20 | 'unix' 21 | ], 22 | 'quotes': [ 23 | 'error', 24 | 'single' 25 | ], 26 | 'no-trailing-spaces': 1, 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: Bug report 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Logs** 27 | If applicable, add relevant FileBrowser logs entries from ```/private/logs/app.log``` or web server logs. 28 | 29 | **Environment (please complete the following information):** 30 | - FileBrowser Version [e.g. 7.0.0] 31 | - Server: [e.g. Apache 2.4 on Debian Linux] 32 | - PHP Version [e.g. PHP 7.3] 33 | - Browser [e.g. chrome, safari] 34 | 35 | **Additional context** 36 | Add any other context about the problem here. 37 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [10.x, 12.x, 14.x] 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v1 17 | 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | 23 | - name: Cypress dependencies 24 | run: sudo apt-get install -y libgtk2.0-0 libgtk-3-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb 25 | 26 | - name: npm install, build, and test 27 | run: | 28 | npm install 29 | npm run lint 30 | npm run test:e2e 31 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | php-version: ['8.0', '8.1', '8.2'] 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v1 18 | 19 | - name: Setup PHP ${{ matrix.php-version }} 20 | uses: shivammathur/setup-php@v2 21 | with: 22 | php-version: ${{ matrix.php-version }} 23 | extensions: mbstring, zip, sqlite3, filter 24 | coverage: xdebug 25 | 26 | - name: Install Dependencies 27 | run: composer install --no-interaction 28 | 29 | - name: Copy configuration.php 30 | run: cp configuration_sample.php configuration.php 31 | 32 | - name: Execute Tests 33 | run: vendor/bin/phpunit 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | vendor 3 | vendor.* 4 | dist/css 5 | dist/js 6 | dist/main.html 7 | 8 | configuration.php 9 | 10 | tests/backend/coverage 11 | tests/backend/tmp/repository/* 12 | tests/frontend/e2e/videos/ 13 | tests/frontend/e2e/screenshots/ 14 | 15 | docs/_build/* 16 | 17 | # Log files 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | 22 | # Cache files 23 | .*.cache 24 | .couscous/ 25 | 26 | # Editor directories and files 27 | .DS_Store 28 | tags 29 | .idea 30 | .vscode 31 | *.suo 32 | *.ntvs* 33 | *.njsproj 34 | *.sln 35 | *.sw* 36 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | exclude('vendor') 5 | ->in(__DIR__) 6 | ; 7 | 8 | return PhpCsFixer\Config::create() 9 | ->setUsingCache(false) 10 | ->setRules([ 11 | '@PhpCsFixer' => true, 12 | 'yoda_style' => null, 13 | 'not_operator_with_successor_space' => true, 14 | 'php_unit_test_class_requires_covers' => false, 15 | ]) 16 | ->setFinder($finder) 17 | ; 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Any violations of the code of conduct may be reported to Foreach Code Factory (services@etista.com): 4 | 5 | - Participants will be tolerant of opposing views. 6 | - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. 7 | - When interpreting the words and actions of others, participants should always assume good intentions. 8 | - Behavior which can be reasonably considered harassment will not be tolerated. 9 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing to FileBrowser 2 | 3 | Please note we have a code of conduct, please follow it in all your interactions with the project. 4 | 5 | - Before starting to write code, talk to a maintainer and discuss proposed changes 6 | - File an issue before submitting a pull request 7 | - Please make sure continuous integration passes 8 | 9 | ## Where to report bugs? 10 | 11 | - Please report all bugs in this repository's issues tracker. 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021, Foreach Code Factory. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /backend/App.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser; 13 | 14 | use Filebrowser\Config\Config; 15 | use Filebrowser\Container\Container; 16 | use Filebrowser\Kernel\Request; 17 | use Filebrowser\Kernel\Response; 18 | use Filebrowser\Kernel\StreamedResponse; 19 | 20 | class App 21 | { 22 | private $container; 23 | 24 | public function __construct(Config $config, Request $request, Response $response, StreamedResponse $sresponse, Container $container) 25 | { 26 | $container->set(Config::class, $config); 27 | $container->set(Container::class, $container); 28 | $container->set(Request::class, $request); 29 | $container->set(Response::class, $response); 30 | $container->set(StreamedResponse::class, $sresponse); 31 | 32 | foreach ($config->get('services', []) as $key => $service) { 33 | $container->set($key, $container->get($service['handler'])); 34 | $container->get($key)->init(isset($service['config']) ? $service['config'] : []); 35 | } 36 | 37 | $response->send(); 38 | 39 | $this->container = $container; 40 | } 41 | 42 | public function resolve($name) 43 | { 44 | return $this->container->get($name); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /backend/Config/Config.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Config; 13 | 14 | class Config 15 | { 16 | protected $config; 17 | 18 | public function __construct(array $config = []) 19 | { 20 | $this->config = $config; 21 | 22 | $timezone = isset($this->config['timezone']) ? $this->config['timezone'] : 'UTC'; 23 | date_default_timezone_set($timezone); 24 | } 25 | 26 | public function get($key = null, $default = null) 27 | { 28 | if (is_null($key)) { 29 | return $this->config; 30 | } 31 | 32 | $key = is_array($key) ? $key : explode('.', $key); 33 | 34 | $target = $this->config; 35 | 36 | while (! is_null($segment = array_shift($key))) { 37 | if (is_array($target) && array_key_exists($segment, $target)) { 38 | $target = $target[$segment]; 39 | } else { 40 | return $default; 41 | } 42 | } 43 | 44 | return $target; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /backend/Container/Container.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Container; 13 | 14 | use DI\Container as PHPDIContainer; 15 | 16 | class Container extends PHPDIContainer implements ContainerInterface 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /backend/Container/ContainerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Container; 13 | 14 | interface ContainerInterface 15 | { 16 | public function get($name); 17 | 18 | public function set(string $name, $value); 19 | 20 | public function call($callable, array $parameters = []); 21 | } 22 | -------------------------------------------------------------------------------- /backend/Controllers/AuthController.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Controllers; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Kernel\Response; 16 | use Filebrowser\Services\Auth\AuthInterface; 17 | use Filebrowser\Services\Logger\LoggerInterface; 18 | use Rakit\Validation\Validator; 19 | 20 | class AuthController 21 | { 22 | protected $logger; 23 | 24 | public function __construct(LoggerInterface $logger) 25 | { 26 | $this->logger = $logger; 27 | } 28 | 29 | public function login(Request $request, Response $response, AuthInterface $auth) 30 | { 31 | $username = $request->input('username'); 32 | $password = $request->input('password'); 33 | 34 | if ($auth->authenticate($username, $password)) { 35 | $this->logger->log("Logged in {$username} from IP ".$request->getClientIp()); 36 | 37 | return $response->json($auth->user()); 38 | } 39 | 40 | $this->logger->log("Login failed for {$username} from IP ".$request->getClientIp()); 41 | 42 | return $response->json('Login failed, please try again', 422); 43 | } 44 | 45 | public function logout(Response $response, AuthInterface $auth) 46 | { 47 | return $response->json($auth->forget()); 48 | } 49 | 50 | public function getUser(Response $response, AuthInterface $auth) 51 | { 52 | $user = $auth->user() ?: $auth->getGuest(); 53 | 54 | return $response->json($user); 55 | } 56 | 57 | public function changePassword(Request $request, Response $response, AuthInterface $auth, Validator $validator) 58 | { 59 | $validator->setMessage('required', 'This field is required'); 60 | $validation = $validator->validate($request->all(), [ 61 | 'oldpassword' => 'required', 62 | 'newpassword' => 'required', 63 | ]); 64 | 65 | if ($validation->fails()) { 66 | $errors = $validation->errors(); 67 | 68 | return $response->json($errors->firstOfAll(), 422); 69 | } 70 | 71 | if (! $auth->authenticate($auth->user()->getUsername(), $request->input('oldpassword'))) { 72 | return $response->json(['oldpassword' => 'Wrong password'], 422); 73 | } 74 | 75 | return $response->json($auth->update($auth->user()->getUsername(), $auth->user(), $request->input('newpassword'))); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /backend/Controllers/ErrorController.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Controllers; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Kernel\Response; 16 | 17 | class ErrorController 18 | { 19 | protected $request_type; 20 | 21 | public function __construct(Request $request) 22 | { 23 | $this->request_type = $request->getContentType(); 24 | } 25 | 26 | public function notFound(Response $response) 27 | { 28 | return $this->request_type == 'json' ? $response->json('Not Found', 404) : $response->html('Not Found', 404); 29 | } 30 | 31 | public function methodNotAllowed(Response $response) 32 | { 33 | return $this->request_type == 'json' ? $response->json('Not Allowed', 401) : $response->html('Not Found', 401); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /backend/Controllers/ViewController.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Controllers; 13 | 14 | use Filebrowser\Config\Config; 15 | use Filebrowser\Kernel\Response; 16 | use Filebrowser\Services\View\ViewInterface; 17 | 18 | class ViewController 19 | { 20 | public function index(Response $response, ViewInterface $view) 21 | { 22 | return $response->html($view->getIndexPage()); 23 | } 24 | 25 | public function getFrontendConfig(Response $response, Config $config) 26 | { 27 | return $response->json($config->get('frontend_config')); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /backend/Kernel/Request.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Kernel; 13 | 14 | use Symfony\Component\HttpFoundation\Request as SymfonyRequest; 15 | 16 | class Request extends SymfonyRequest 17 | { 18 | public function input($key, $default = null) 19 | { 20 | // first try GET, then POST 21 | $value = $this->get($key, $this->query->get($key)); 22 | 23 | // then look into JSON content, fallback to default 24 | if ($value === null) { 25 | $content = json_decode((string) $this->getContent()); 26 | $value = isset($content->{$key}) ? $content->{$key} : $default; 27 | } 28 | 29 | return $value; 30 | } 31 | 32 | public function all() 33 | { 34 | $params = []; 35 | 36 | // first look into JSON content 37 | $content = json_decode((string) $this->getContent()); 38 | if (! empty($content)) { 39 | foreach ($content as $key => $param) { 40 | $params[$key] = $param; 41 | } 42 | } 43 | 44 | // then try (and override) with POST 45 | foreach ($this->request as $key => $param) { 46 | $params[$key] = $param; 47 | } 48 | 49 | // finally try (and override) with GET 50 | foreach ($this->query as $key => $param) { 51 | $params[$key] = $param; 52 | } 53 | 54 | return $params; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /backend/Kernel/Response.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Kernel; 13 | 14 | use Symfony\Component\HttpFoundation\Response as SymfonyResponse; 15 | 16 | class Response extends SymfonyResponse 17 | { 18 | public function json($content, $status_code = 200) 19 | { 20 | $this->headers->set('Content-Type', 'application/json'); 21 | $this->setStatusCode($status_code); 22 | 23 | $this->setContent(json_encode([ 24 | 'data' => $content, 25 | ])); 26 | } 27 | 28 | public function html($content, $status_code = 200) 29 | { 30 | $this->setStatusCode($status_code); 31 | $this->setContent($content); 32 | } 33 | 34 | public function redirect($url, $status_code = 302) 35 | { 36 | $this->setStatusCode($status_code); 37 | $this->setContent( 38 | sprintf(' 39 | 40 | 41 | 42 | 43 | Redirecting to %1$s 44 | 45 | 46 | Redirecting to %1$s. 47 | 48 | ', htmlspecialchars($url, ENT_QUOTES, 'UTF-8')) 49 | ); 50 | $this->headers->set('Location', $url); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /backend/Kernel/StreamedResponse.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Kernel; 13 | 14 | use Symfony\Component\HttpFoundation\StreamedResponse as SymfonyStreamedResponse; 15 | 16 | class StreamedResponse extends SymfonyStreamedResponse 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /backend/Services/Archiver/ArchiverInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Archiver; 13 | 14 | use Filebrowser\Services\Storage\Filesystem; 15 | 16 | interface ArchiverInterface 17 | { 18 | public function createArchive(Filesystem $storage): string; 19 | 20 | public function uncompress(string $source, string $destination, Filesystem $storage); 21 | 22 | public function addDirectoryFromStorage(string $path); 23 | 24 | public function addFileFromStorage(string $path); 25 | 26 | public function closeArchive(); 27 | 28 | public function storeArchive($destination, $name); 29 | } 30 | -------------------------------------------------------------------------------- /backend/Services/Auth/AuthInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Auth; 13 | 14 | interface AuthInterface 15 | { 16 | public function user(): ?User; 17 | 18 | public function authenticate($username, $password): bool; 19 | 20 | public function forget(); 21 | 22 | public function find($username): ?User; 23 | 24 | public function store(User $user); 25 | 26 | public function update($username, User $user, $password = ''): User; 27 | 28 | public function add(User $user, $password): User; 29 | 30 | public function delete(User $user); 31 | 32 | public function getGuest(): User; 33 | 34 | public function allUsers(): UsersCollection; 35 | } 36 | -------------------------------------------------------------------------------- /backend/Services/Auth/UsersCollection.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Auth; 13 | 14 | use Filebrowser\Utils\Collection; 15 | 16 | class UsersCollection implements \JsonSerializable 17 | { 18 | use Collection; 19 | 20 | public function addUser(User $user) 21 | { 22 | $this->add($user); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /backend/Services/Cors/Cors.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Cors; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Kernel\Response; 16 | use Filebrowser\Services\Service; 17 | 18 | /** 19 | * @codeCoverageIgnore 20 | */ 21 | class Cors implements Service 22 | { 23 | protected $request; 24 | 25 | protected $response; 26 | 27 | public function __construct(Request $request, Response $response) 28 | { 29 | $this->request = $request; 30 | $this->response = $response; 31 | } 32 | 33 | public function init(array $config = []) 34 | { 35 | if ($config['enabled'] !== true) { 36 | return; 37 | } 38 | 39 | $this->response->headers->set('Access-Control-Allow-Origin', $this->request->headers->get('Origin')); 40 | $this->response->headers->set('Access-Control-Allow-Credentials', 'true'); 41 | $this->response->headers->set('Access-Control-Expose-Headers', 'x-csrf-token'); 42 | 43 | if ($this->request->server->get('REQUEST_METHOD') == 'OPTIONS') { 44 | $this->response->headers->set('Access-Control-Allow-Headers', 'content-type, x-csrf-token'); 45 | $this->response->send(); 46 | die; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /backend/Services/Logger/Adapters/MonoLogger.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Logger\Adapters; 13 | 14 | use Filebrowser\Services\Logger\LoggerInterface; 15 | use Filebrowser\Services\Service; 16 | use Monolog\ErrorHandler; 17 | use Monolog\Logger; 18 | 19 | class MonoLogger implements Service, LoggerInterface 20 | { 21 | protected $logger; 22 | 23 | public function init(array $config = []) 24 | { 25 | $this->logger = new Logger('default'); 26 | 27 | foreach ($config['monolog_handlers'] as $handler) { 28 | $this->logger->pushHandler($handler()); 29 | } 30 | 31 | $handler = new ErrorHandler($this->logger); 32 | $handler->registerErrorHandler([], true); 33 | $handler->registerFatalHandler(); 34 | } 35 | 36 | public function log(string $message, int $level = Logger::INFO) 37 | { 38 | $this->logger->log($level, $message); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /backend/Services/Logger/LoggerInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Logger; 13 | 14 | interface LoggerInterface 15 | { 16 | public function log(string $message, int $level); 17 | } 18 | -------------------------------------------------------------------------------- /backend/Services/Process/SymfonyProcessFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Process; 13 | 14 | use Filebrowser\Services\ServiceFactory; 15 | use Symfony\Component\Process\Process; 16 | 17 | class SymfonyProcessFactory implements ServiceFactory 18 | { 19 | protected $config; 20 | 21 | public function init(array $config = []) 22 | { 23 | $this->config = $config; 24 | } 25 | 26 | public function createService(array $params) 27 | { 28 | return new Process($params); 29 | } 30 | } -------------------------------------------------------------------------------- /backend/Services/Router/Router.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Router; 13 | 14 | use FastRoute; 15 | use Filebrowser\Container\Container; 16 | use Filebrowser\Kernel\Request; 17 | use Filebrowser\Services\Auth\AuthInterface; 18 | use Filebrowser\Services\Service; 19 | 20 | class Router implements Service 21 | { 22 | protected $request; 23 | 24 | protected $auth; 25 | 26 | protected $container; 27 | 28 | protected $user; 29 | 30 | public function __construct(Request $request, AuthInterface $auth, Container $container) 31 | { 32 | $this->request = $request; 33 | $this->container = $container; 34 | $this->user = $auth->user() ?: $auth->getGuest(); 35 | } 36 | 37 | public function init(array $config = []) 38 | { 39 | $uri = '/'; 40 | $http_method = $this->request->getMethod(); 41 | 42 | if ($r = $this->request->query->get($config['query_param'])) { 43 | $this->request->query->remove($config['query_param']); 44 | $uri = rawurldecode($r); 45 | } 46 | 47 | $routesBase = require $config['routes_file']; 48 | 49 | $routes = array_merge($routesBase, require $config['routes_optional_file']); 50 | 51 | $dispatcher = FastRoute\simpleDispatcher(function (FastRoute\RouteCollector $r) use ($routes) { 52 | if ($routes && ! empty($routes)) { 53 | foreach ($routes as $params) { 54 | if ($this->user->hasRole($params['roles']) && $this->user->hasPermissions($params['permissions'])) { 55 | $r->addRoute($params['route'][0], $params['route'][1], $params['route'][2]); 56 | } 57 | } 58 | } 59 | }); 60 | 61 | $routeInfo = $dispatcher->dispatch($http_method, $uri); 62 | 63 | $controller = '\Filebrowser\Controllers\ErrorController'; 64 | $action = 'notFound'; 65 | $params = []; 66 | 67 | switch ($routeInfo[0]) { 68 | case FastRoute\Dispatcher::FOUND: 69 | $handler = explode('@', $routeInfo[1]); 70 | $controller = $handler[0]; 71 | $action = $handler[1]; 72 | $params = $routeInfo[2]; 73 | 74 | break; 75 | case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: 76 | $action = 'methodNotAllowed'; 77 | 78 | break; 79 | } 80 | 81 | $this->container->call([$controller, $action], $params); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /backend/Services/Security/Security.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Security; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Kernel\Response; 16 | use Filebrowser\Services\Service; 17 | use Filebrowser\Services\Logger\LoggerInterface; 18 | use Symfony\Component\Security\Csrf\CsrfToken; 19 | use Symfony\Component\Security\Csrf\CsrfTokenManager; 20 | 21 | /** 22 | * @codeCoverageIgnore 23 | */ 24 | class Security implements Service 25 | { 26 | protected $request; 27 | 28 | protected $response; 29 | 30 | protected $logger; 31 | 32 | public function __construct(Request $request, Response $response, LoggerInterface $logger) 33 | { 34 | $this->request = $request; 35 | $this->response = $response; 36 | $this->logger = $logger; 37 | } 38 | 39 | public function init(array $config = []) 40 | { 41 | if ($config['csrf_protection']) { 42 | 43 | $key = isset($config['csrf_key']) ? $config['csrf_key'] : 'protection'; 44 | 45 | $http_method = $this->request->getMethod(); 46 | $csrfManager = new CsrfTokenManager(); 47 | 48 | if (in_array($http_method, ['GET', 'HEAD', 'OPTIONS'])) { 49 | $this->response->headers->set('X-CSRF-Token', $csrfManager->getToken($key)); 50 | } else { 51 | $token = new CsrfToken($key, $this->request->headers->get('X-CSRF-Token')); 52 | 53 | if (! $csrfManager->isTokenValid($token)) { 54 | $this->logger->log("Csrf token not valid"); 55 | die; 56 | } 57 | } 58 | } 59 | 60 | if (! empty($config['ip_whitelist'])) $config['ip_allowlist'] = $config['ip_whitelist']; // deprecated, compatibility 61 | 62 | if (! empty($config['ip_allowlist'])) { 63 | $pass = false; 64 | foreach ($config['ip_allowlist'] as $ip) { 65 | if ($this->request->getClientIp() == $ip) { 66 | $pass = true; 67 | } 68 | } 69 | if (! $pass) { 70 | $this->response->setStatusCode(403); 71 | $this->response->send(); 72 | $this->logger->log("Forbidden - IP not found in allowlist ".$this->request->getClientIp()); 73 | die; 74 | } 75 | } 76 | 77 | if (! empty($config['ip_blacklist'])) $config['ip_denylist'] = $config['ip_blacklist']; // deprecated, compatibility 78 | 79 | if (! empty($config['ip_denylist'])) { 80 | $pass = true; 81 | foreach ($config['ip_denylist'] as $ip) { 82 | if ($this->request->getClientIp() == $ip) { 83 | $pass = false; 84 | } 85 | } 86 | if (! $pass) { 87 | $this->response->setStatusCode(403); 88 | $this->response->send(); 89 | $this->logger->log("Forbidden - IP matched against denylist ".$this->request->getClientIp()); 90 | die; 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /backend/Services/Service.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services; 13 | 14 | interface Service 15 | { 16 | public function init(array $config = []); 17 | } 18 | -------------------------------------------------------------------------------- /backend/Services/ServiceFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services; 13 | 14 | interface ServiceFactory extends Service 15 | { 16 | public function createService(array $params); 17 | } 18 | -------------------------------------------------------------------------------- /backend/Services/Session/Adapters/SessionStorage.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Session\Adapters; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Services\Service; 16 | use Filebrowser\Services\Session\Session; 17 | use Filebrowser\Services\Session\SessionStorageInterface; 18 | 19 | class SessionStorage implements Service, SessionStorageInterface 20 | { 21 | protected $request; 22 | 23 | protected $config; 24 | 25 | public function __construct(Request $request) 26 | { 27 | $this->request = $request; 28 | } 29 | 30 | public function init(array $config = []) 31 | { 32 | // we don't have a previous session attached 33 | if (! $this->getSession()) { 34 | $handler = $config['handler']; 35 | $session = new Session($handler()); 36 | $session->setName('filebrowser'); 37 | 38 | $this->setSession($session); 39 | } 40 | } 41 | 42 | public function save() 43 | { 44 | $this->getSession()->save(); 45 | } 46 | 47 | public function set(string $key, $data) 48 | { 49 | return $this->getSession()->set($key, $data); 50 | } 51 | 52 | public function get(string $key, $default = null) 53 | { 54 | return $this->getSession() ? $this->getSession()->get($key, $default) : $default; 55 | } 56 | 57 | public function invalidate() 58 | { 59 | if (! $this->getSession()->isStarted()) { 60 | $this->getSession()->start(); 61 | } 62 | 63 | $this->getSession()->invalidate(); 64 | } 65 | 66 | private function setSession(Session $session) 67 | { 68 | return $this->request->setSession($session); 69 | } 70 | 71 | private function getSession(): ?Session 72 | { 73 | return $this->request->getSession(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /backend/Services/Session/Session.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Session; 13 | 14 | use Symfony\Component\HttpFoundation\Session\Session as SymfonySession; 15 | 16 | class Session extends SymfonySession 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /backend/Services/Session/SessionStorageInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Session; 13 | 14 | interface SessionStorageInterface 15 | { 16 | public function set(string $key, $data); 17 | 18 | public function get(string $key, $default = null); 19 | 20 | public function invalidate(); 21 | 22 | public function save(); 23 | } 24 | -------------------------------------------------------------------------------- /backend/Services/Storage/DirectoryCollection.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Storage; 13 | 14 | use Filebrowser\Utils\Collection; 15 | 16 | class DirectoryCollection implements \JsonSerializable 17 | { 18 | use Collection; 19 | 20 | protected $location; 21 | 22 | public function __construct($location) 23 | { 24 | $this->location = $location; 25 | } 26 | 27 | public function addFile(string $type, string $path, string $name, int $size, int $timestamp) 28 | { 29 | if (! in_array($type, ['dir', 'file', 'back'])) { 30 | throw new \Exception('Invalid file type.'); 31 | } 32 | 33 | $this->add([ 34 | 'type' => $type, 35 | 'path' => $path, 36 | 'name' => $name, 37 | 'size' => $size, 38 | 'time' => $timestamp, 39 | ]); 40 | } 41 | 42 | public function resetTimestamps($timestamp = 0) 43 | { 44 | foreach ($this->items as &$item) { 45 | $item['time'] = $timestamp; 46 | } 47 | } 48 | 49 | public function jsonSerialize() 50 | { 51 | $this->sortByValue('type'); 52 | 53 | return [ 54 | 'location' => $this->location, 55 | 'files' => $this->items, 56 | ]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /backend/Services/Tmpfs/TmpfsInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\Tmpfs; 13 | 14 | interface TmpfsInterface 15 | { 16 | public function exists(string $filename): bool; 17 | 18 | public function findAll($pattern): array; 19 | 20 | public function write(string $filename, $data, $append); 21 | 22 | public function read(string $filename): string; 23 | 24 | public function readStream(string $filename): array; 25 | 26 | public function remove(string $filename); 27 | 28 | public function getFileLocation(string $filename): string; 29 | 30 | public function clean(int $older_than); 31 | } 32 | -------------------------------------------------------------------------------- /backend/Services/View/Adapters/Vuejs.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\View\Adapters; 13 | 14 | use Filebrowser\Config\Config; 15 | use Filebrowser\Services\Service; 16 | use Filebrowser\Services\View\ViewInterface; 17 | 18 | class Vuejs implements Service, ViewInterface 19 | { 20 | private $config; 21 | 22 | public function __construct(Config $config) 23 | { 24 | $this->config = $config; 25 | } 26 | 27 | public function init(array $config = []) 28 | { 29 | $this->add_to_head = isset($config['add_to_head']) ? $config['add_to_head'] : ''; 30 | $this->add_to_body = isset($config['add_to_body']) ? $config['add_to_body'] : ''; 31 | } 32 | 33 | public function getIndexPage() 34 | { 35 | $title = $this->config->get('frontend_config.app_name'); 36 | $public_path = $this->config->get('public_path'); 37 | $public_dir = $this->config->get('public_dir'); 38 | 39 | return ' 40 | 41 | 42 | 43 | 44 | 45 | 46 | '.$title.' 47 | '.$this->add_to_head.' 48 | 49 | 50 | 51 | 52 | 53 |
54 | 55 | 56 | 57 | '.$this->add_to_body.' 58 | 59 | 60 | '; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /backend/Services/View/ViewInterface.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Services\View; 13 | 14 | interface ViewInterface 15 | { 16 | public function getIndexPage(); 17 | } 18 | -------------------------------------------------------------------------------- /backend/Utils/Collection.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Utils; 13 | 14 | trait Collection 15 | { 16 | protected $items = []; 17 | 18 | public function add($obj) 19 | { 20 | return $this->items[] = $obj; 21 | } 22 | 23 | public function delete($obj) 24 | { 25 | foreach ($this->items as $key => $item) { 26 | if ($item === $obj) { 27 | unset($this->items[$key]); 28 | } 29 | } 30 | } 31 | 32 | public function all() 33 | { 34 | return $this->items; 35 | } 36 | 37 | public function length() 38 | { 39 | return count($this->items); 40 | } 41 | 42 | public function jsonSerialize() 43 | { 44 | return $this->items; 45 | } 46 | 47 | public function sortByValue($value, $desc = false) 48 | { 49 | usort($this->items, function ($a, $b) use ($value) { 50 | return $a[$value] <=> $b[$value]; 51 | }); 52 | 53 | if ($desc) { 54 | $this->items = array_reverse($this->items); 55 | } 56 | 57 | return $this; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /backend/Utils/PasswordHash.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Filebrowser\Utils; 13 | 14 | /** 15 | * @codeCoverageIgnore 16 | */ 17 | trait PasswordHash 18 | { 19 | public static function hashPassword($value) 20 | { 21 | $hash = password_hash($value, PASSWORD_BCRYPT); 22 | 23 | if ($hash === false) { 24 | throw new \Exception('Bcrypt hashing not supported.'); 25 | } 26 | 27 | return $hash; 28 | } 29 | 30 | public static function verifyPassword($value, $hash) 31 | { 32 | return password_verify($value, $hash); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /composer.74.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linuxforphp/filebrowser", 3 | "description": "Filebrowser", 4 | "license": "Apache-2.0", 5 | "type": "project", 6 | "config": { 7 | "platform": { 8 | "php": "7.2.5" 9 | } 10 | }, 11 | "require": { 12 | "php": "^7.2", 13 | "monolog/monolog": "^1.24", 14 | "nikic/fast-route": "^1.3", 15 | "symfony/security-csrf": "^4.4", 16 | "symfony/http-foundation": "^4.4", 17 | "dibi/dibi": "^4.1", 18 | "php-di/php-di": "^6.0", 19 | "rakit/validation": "^1.1", 20 | "league/flysystem": "^1.1", 21 | "league/flysystem-ziparchive": "^1.0", 22 | "symfony/process": "^5.3" 23 | }, 24 | "authors": [ 25 | { 26 | "name": "LfPHP Services", 27 | "email": "services@linuxforphp.com" 28 | }, 29 | { 30 | "name": "Milos Stojanovic", 31 | "email": "alcalbg@gmail.com" 32 | } 33 | ], 34 | "autoload": { 35 | "psr-4": { 36 | "Filebrowser\\": "backend" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Tests\\": "tests/backend/" 42 | } 43 | }, 44 | "require-dev": { 45 | "phpunit/phpunit": "^8.0", 46 | "symfony/var-dumper": "^4.4", 47 | "league/flysystem-memory": "^1.0", 48 | "phpstan/phpstan": "^0.11.8", 49 | "linuxforphp/linuxforcomposer": "2.0.9.2" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linuxforphp/filebrowser", 3 | "description": "Filebrowser", 4 | "license": "Apache-2.0", 5 | "type": "project", 6 | "config": { 7 | "platform": { 8 | "php": "8.0.0" 9 | } 10 | }, 11 | "require": { 12 | "php": "^8.0", 13 | "monolog/monolog": "^1.24", 14 | "nikic/fast-route": "^1.3", 15 | "symfony/security-csrf": "^4.4", 16 | "symfony/http-foundation": "^4.4", 17 | "dibi/dibi": "^4.1", 18 | "php-di/php-di": "^6.0", 19 | "rakit/validation": "^1.1", 20 | "league/flysystem": "^1.1", 21 | "league/flysystem-ziparchive": "^1.0", 22 | "symfony/process": "^5.3" 23 | }, 24 | "authors": [ 25 | { 26 | "name": "LfPHP Services", 27 | "email": "services@linuxforphp.com" 28 | }, 29 | { 30 | "name": "Milos Stojanovic", 31 | "email": "alcalbg@gmail.com" 32 | } 33 | ], 34 | "autoload": { 35 | "psr-4": { 36 | "Filebrowser\\": "backend" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Tests\\": "tests/backend/" 42 | } 43 | }, 44 | "require-dev": { 45 | "phpunit/phpunit": "^8.0", 46 | "symfony/var-dumper": "^4.4", 47 | "league/flysystem-memory": "^1.0", 48 | "phpstan/phpstan": "^1.10.14", 49 | "linuxforphp/linuxforcomposer": "2.0.9.2" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /config/routes.optional.config.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'POST', '/zipitems', '\Filebrowser\Controllers\FileController@zipItemsProc', 8 | ], 9 | 'roles' => [ 10 | 'guest', 'user', 'admin', 11 | ], 12 | 'permissions' => [ 13 | 'read', 'write', 'zip', 14 | ], 15 | ], 16 | [ 17 | 'route' => [ 18 | 'POST', '/unzipitem', '\Filebrowser\Controllers\FileController@unzipItemProc', 19 | ], 20 | 'roles' => [ 21 | 'guest', 'user', 'admin', 22 | ], 23 | 'permissions' => [ 24 | 'read', 'write', 'zip', 25 | ], 26 | ], 27 | [ 28 | 'route' => [ 29 | 'POST', '/batchdownload', '\Filebrowser\Controllers\DownloadController@batchDownloadCreateProc', 30 | ], 31 | 'roles' => [ 32 | 'guest', 'user', 'admin', 33 | ], 34 | 'permissions' => [ 35 | 'read', 'download', 'batchdownload', 36 | ], 37 | ], 38 | ]; 39 | } else { 40 | return [ 41 | [ 42 | 'route' => [ 43 | 'POST', '/zipitems', '\Filebrowser\Controllers\FileController@zipItems', 44 | ], 45 | 'roles' => [ 46 | 'guest', 'user', 'admin', 47 | ], 48 | 'permissions' => [ 49 | 'read', 'write', 'zip', 50 | ], 51 | ], 52 | [ 53 | 'route' => [ 54 | 'POST', '/unzipitem', '\Filebrowser\Controllers\FileController@unzipItem', 55 | ], 56 | 'roles' => [ 57 | 'guest', 'user', 'admin', 58 | ], 59 | 'permissions' => [ 60 | 'read', 'write', 'zip', 61 | ], 62 | ], 63 | [ 64 | 'route' => [ 65 | 'POST', '/batchdownload', '\Filebrowser\Controllers\DownloadController@batchDownloadCreate', 66 | ], 67 | 'roles' => [ 68 | 'guest', 'user', 'admin', 69 | ], 70 | 'permissions' => [ 71 | 'read', 'download', 'batchdownload', 72 | ], 73 | ], 74 | ]; 75 | } 76 | -------------------------------------------------------------------------------- /couscous.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - docs 3 | 4 | cname: filebrowser.linuxforphp.net 5 | 6 | branch: gh-pages 7 | 8 | title: FileBrowser - Documentation 9 | titleShort: FileBrowser 10 | subTitle: Documentation 11 | 12 | baseUrl: https://filebrowser.linuxforphp.net 13 | 14 | template: 15 | directory: docs/template/ 16 | 17 | github: 18 | user: filebrowser 19 | repo: filebrowser 20 | 21 | menu: 22 | sections: 23 | main: 24 | name: Getting Started 25 | items: 26 | home: 27 | text: What is FileBrowser 28 | relativeUrl: index.html 29 | install: 30 | text: Installation 31 | relativeUrl: install.html 32 | account: 33 | text: Users 34 | relativeUrl: accounts.html 35 | development: 36 | text: Development 37 | relativeUrl: development.html 38 | demo: 39 | text: Demo 40 | relativeUrl: demo.html 41 | config: 42 | name: Configuration 43 | items: 44 | basic: 45 | text: Basic 46 | relativeUrl: configuration/basic.html 47 | auth: 48 | text: Auth 49 | relativeUrl: configuration/auth.html 50 | sessions: 51 | text: Session 52 | relativeUrl: configuration/session.html 53 | storage: 54 | text: Storage 55 | relativeUrl: configuration/storage.html 56 | logging: 57 | text: Logging 58 | relativeUrl: configuration/logging.html 59 | security: 60 | text: Security 61 | relativeUrl: configuration/security.html 62 | router: 63 | text: Router 64 | relativeUrl: configuration/router.html 65 | tmpfs: 66 | text: Tmpfs 67 | relativeUrl: configuration/tmpfs.html 68 | 69 | multilang: 70 | name: Languages 71 | items: 72 | default: 73 | text: Translations 74 | relativeUrl: translations/default.html 75 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "pluginsFile": "tests/frontend/e2e/plugins/index.js", 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /data/filebrowser_package_create.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # IMPORTANT: SET THE LINUXFORCOMPOSER MOUNT POINT TO /srv/filebrowser 3 | export FILEBROWSER_PKG_VERSION=8.0.2 4 | tar -C /srv \ 5 | --exclude='filebrowser/.env.local' \ 6 | --exclude='filebrowser/.env.production' \ 7 | --exclude='filebrowser/.git' \ 8 | --exclude='filebrowser/.github' \ 9 | --exclude='filebrowser/.gitignore' \ 10 | --exclude='filebrowser/.idea' \ 11 | --exclude='filebrowser/docs' \ 12 | --exclude='filebrowser/frontend' \ 13 | --exclude='filebrowser/node_modules' \ 14 | --exclude='filebrowser/tests' \ 15 | --exclude='filebrowser/.eslintrc.js' \ 16 | --exclude='filebrowser/.php_cs' \ 17 | --exclude='filebrowser/.phpunit.result.cache' \ 18 | --exclude='filebrowser/babel.config.js' \ 19 | --exclude='filebrowser/CHANGELOG.md' \ 20 | --exclude='filebrowser/CODE_OF_CONDUCT.md' \ 21 | --exclude='filebrowser/configuration.php' \ 22 | --exclude='filebrowser/CONTRIBUTING.md' \ 23 | --exclude='filebrowser/couscous.yml' \ 24 | --exclude='filebrowser/cypress.json' \ 25 | --exclude='filebrowser/data' \ 26 | --exclude='filebrowser/jest.config.js' \ 27 | --exclude='filebrowser/linuxforcomposer.json' \ 28 | --exclude='filebrowser/phpunit.xml' \ 29 | --exclude='filebrowser/postcss.config.js' \ 30 | --exclude='filebrowser/README.md' \ 31 | --exclude='filebrowser/vue.config.js' \ 32 | --exclude='filebrowser/repository/.gitignore' \ 33 | -czvf /srv/filebrowser-$FILEBROWSER_PKG_VERSION.tar.gz \ 34 | filebrowser/ 35 | mkdir -p /srv/zip 36 | cd /srv/zip || exit 1 37 | tar -xvf /srv/filebrowser-$FILEBROWSER_PKG_VERSION.tar.gz 38 | zip -r filebrowser-$FILEBROWSER_PKG_VERSION.zip filebrowser/ 39 | mv filebrowser-$FILEBROWSER_PKG_VERSION.zip .. 40 | cd /srv || exit 1 41 | rm -rf zip/ 42 | mv filebrowser-$FILEBROWSER_PKG_VERSION.tar.gz /srv/filebrowser/data 43 | mv filebrowser-$FILEBROWSER_PKG_VERSION.zip /srv/filebrowser/data 44 | chown 1000:1000 /srv/filebrowser/data/filebrowser-$FILEBROWSER_PKG_VERSION.tar.gz 45 | chown 1000:1000 /srv/filebrowser/data/filebrowser-$FILEBROWSER_PKG_VERSION.zip 46 | cd 47 | -------------------------------------------------------------------------------- /dist/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/favicon.ico -------------------------------------------------------------------------------- /dist/fonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-brands-400.eot -------------------------------------------------------------------------------- /dist/fonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /dist/fonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-brands-400.woff -------------------------------------------------------------------------------- /dist/fonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /dist/fonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-regular-400.eot -------------------------------------------------------------------------------- /dist/fonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /dist/fonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-regular-400.woff -------------------------------------------------------------------------------- /dist/fonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /dist/fonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-solid-900.eot -------------------------------------------------------------------------------- /dist/fonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /dist/fonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-solid-900.woff -------------------------------------------------------------------------------- /dist/fonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/fonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /dist/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/dist/img/logo.png -------------------------------------------------------------------------------- /dist/index.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | if (! defined('DIR_SEP')) { 14 | define('DIR_SEP', DIRECTORY_SEPARATOR); 15 | } 16 | 17 | if (! defined('APP_ENV')) { 18 | define('APP_ENV', 'production'); 19 | } 20 | 21 | if (! defined('APP_PUBLIC_PATH')) { 22 | define('APP_PUBLIC_PATH', ''); 23 | } 24 | 25 | if (! defined('APP_PUBLIC_DIR')) { 26 | define('APP_PUBLIC_DIR', __DIR__); 27 | } 28 | 29 | if (! defined('APP_ROOT_DIR')) { 30 | define('APP_ROOT_DIR', dirname(__DIR__)); 31 | } 32 | 33 | if (! defined('APP_VERSION')) { 34 | define('APP_VERSION', '8.1.0'); 35 | } 36 | 37 | if (version_compare(PHP_VERSION, '8.0.0', '<')) { 38 | die('Minimum requirement is PHP 8.0.0 You are using: ' . PHP_VERSION); 39 | } 40 | 41 | if (! is_writable(APP_ROOT_DIR . DIR_SEP . 'private' . DIR_SEP . 'logs')) { 42 | die('Folder not writable: /private/logs/'); 43 | } 44 | 45 | if (! is_writable(APP_ROOT_DIR . DIR_SEP . 'repository/')) { 46 | die('Folder not writable: /repository/'); 47 | } 48 | 49 | if (! file_exists(APP_ROOT_DIR . DIR_SEP . 'configuration.php')) { 50 | copy(APP_ROOT_DIR . DIR_SEP . 'configuration_sample.php', APP_ROOT_DIR . DIR_SEP . 'configuration.php'); 51 | } 52 | 53 | require APP_ROOT_DIR . DIR_SEP . 'vendor' . DIR_SEP . 'autoload.php'; 54 | 55 | use Filebrowser\App; 56 | use Filebrowser\Config\Config; 57 | use Filebrowser\Container\Container; 58 | use Filebrowser\Kernel\Request; 59 | use Filebrowser\Kernel\Response; 60 | use Filebrowser\Kernel\StreamedResponse; 61 | 62 | $baseConfig = require APP_ROOT_DIR . DIR_SEP . 'configuration.php'; 63 | 64 | if (isset($baseConfig['storage']['driver']['fastzip']) && $baseConfig['storage']['driver']['fastzip']) { 65 | if (!file_exists(APP_ROOT_DIR . DIR_SEP . 'private' . DIR_SEP . 'tmp' . DIR_SEP . 'zip_path.txt')) { 66 | $handle = popen('whereis zip | awk \'{print $2}\'', 'r'); 67 | $read = fread($handle, 2096); 68 | $zipPath = trim($read); 69 | pclose($handle); 70 | is_executable($zipPath) || die('To use the "fastzip" option, you must have "zip" and "unzip" installed on the Unix/Linux server.'); 71 | 72 | file_put_contents(APP_ROOT_DIR . DIR_SEP . 'private' . DIR_SEP . 'tmp' . DIR_SEP . 'zip_path.txt', trim($read)); 73 | } 74 | 75 | if (!file_exists(APP_ROOT_DIR . DIR_SEP . 'private' . DIR_SEP . 'tmp' . DIR_SEP . 'unzip_path.txt')) { 76 | $handle = popen('whereis unzip | awk \'{print $2}\'', 'r'); 77 | $read = fread($handle, 2096); 78 | $unzipPath = trim($read); 79 | pclose($handle); 80 | is_executable($unzipPath) || die('To use the "fastzip" option, you must have "zip" and "unzip" installed on the Unix/Linux server.'); 81 | 82 | file_put_contents(APP_ROOT_DIR . DIR_SEP . 'private' . DIR_SEP . 'tmp' . DIR_SEP . 'unzip_path.txt', trim($read)); 83 | } 84 | } 85 | 86 | $servicesConfig = require APP_ROOT_DIR . DIR_SEP . 'config' . DIR_SEP . 'services.config.php'; 87 | 88 | $config = new Config( 89 | array_merge( 90 | $baseConfig, 91 | $servicesConfig 92 | ) 93 | ); 94 | 95 | new App($config, Request::createFromGlobals(), new Response(), new StreamedResponse(), new Container()); 96 | -------------------------------------------------------------------------------- /dist/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filebrowser", 3 | "short_name": "filebrowser", 4 | "icons": [ 5 | { 6 | "src": "./img/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "./img/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "./index.html", 17 | "display": "standalone", 18 | "background_color": "#000000", 19 | "theme_color": "#4DBA87" 20 | } 21 | -------------------------------------------------------------------------------- /dist/robots.txt: -------------------------------------------------------------------------------- 1 | # No crawling for robots, also present in the header as meta tag. 2 | # Remove if you want to appear on google search 3 | 4 | User-agent: * 5 | Disallow: / 6 | 7 | -------------------------------------------------------------------------------- /dist/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js"); 15 | 16 | importScripts( 17 | "/precache-manifest.027df767f4c4fdf5651329516a7a6123.js" 18 | ); 19 | 20 | workbox.core.setCacheNameDetails({prefix: "filebrowser"}); 21 | 22 | /** 23 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 24 | * requests for URLs in the manifest. 25 | * See https://goo.gl/S9QRab 26 | */ 27 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 28 | workbox.precaching.suppressWarnings(); 29 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 30 | -------------------------------------------------------------------------------- /docs/accounts.rst: -------------------------------------------------------------------------------- 1 | .. _AccountsAnchor: 2 | 3 | ======== 4 | Accounts 5 | ======== 6 | 7 | .. index:: Accounts 8 | 9 | ---------- 10 | User Roles 11 | ---------- 12 | 13 | .. index:: User roles 14 | 15 | There are three different user roles: 16 | 17 | - Admin (for user and file management), 18 | - User (regular, logged in user), 19 | - Guest (anonymous, not logged in). 20 | 21 | ---------------- 22 | User Permissions 23 | ---------------- 24 | 25 | .. index:: User permissions 26 | 27 | There are 6 different user permissions that the administrator can assign to each user: 28 | 29 | - Read (user can browse and list files and folders), 30 | - Write (user can copy, move, rename, and delete files), 31 | - Upload (user can upload files to the repository), 32 | - Download (user can download files from the repository), 33 | - Batch Download (user can download multiple files and folders at once), 34 | - Zip (user can zip and unzip files). 35 | 36 | Some permissions require others. For example, Batch Download requires 37 | Read permissions (so that the user can list files and select them), as well 38 | as basic Download permissions. 39 | 40 | Guest Account 41 | ------------- 42 | 43 | .. index:: Guest account 44 | 45 | The Guest account is a predefined account, and it is disabled by default since 46 | no permissions are assigned to it. 47 | 48 | The Admin can enable the Guest account, which will allow anyone to interact 49 | with the repository based on the Guest account permissions. 50 | 51 | -------------------------- 52 | Resetting Admin’s Password 53 | -------------------------- 54 | 55 | .. index:: Reset password 56 | 57 | If you forgot your admin password you can follow these steps to reset 58 | it: 59 | 60 | - Backup your current users file ``private/users.json`` to a safe place, 61 | - Copy blank template ``private/users.json.blank`` over 62 | ``private/users.json`` or simply refresh your browser, 63 | - Login as admin with default credentials ``admin/admin123``, 64 | - Put your original users file back to ``private/users.json`` replacing 65 | the template, 66 | - Since you are now logged in as admin, simply go to users page and 67 | change your password, 68 | - Log out and try to login with the new password. 69 | 70 | Note: If you’re using database Auth adapter then simply run this query 71 | to set default password back to ``admin123`` 72 | 73 | :: 74 | 75 | UPDATE `users` 76 | SET `password` = '$2y$10$Nu35w4pteLfc7BDCIkDPkecjw8wsH8Y2GMfIewUbXLT7zzW6WOxwq' 77 | WHERE `username` = 'admin'; 78 | -------------------------------------------------------------------------------- /docs/configuration/logging.rst: -------------------------------------------------------------------------------- 1 | .. _LoggingAnchor: 2 | 3 | ======= 4 | Logging 5 | ======= 6 | 7 | .. index:: Logging 8 | 9 | ------------------------------- 10 | Configuring the Logging Service 11 | ------------------------------- 12 | 13 | .. index:: Logging configuration 14 | 15 | Logging is provided trough the powerful 16 | `Monolog `__ library. Please read 17 | their documentation for more details: https://github.com/Seldaek/monolog. 18 | 19 | The default handler will simply use the ``private/logs/app.log`` file to store 20 | application logs and errors. 21 | 22 | :: 23 | 24 | 'Filebrowser\Services\Logger\LoggerInterface' => [ 25 | 'handler' => '\Filebrowser\Services\Logger\Adapters\MonoLogger', 26 | 'config' => [ 27 | 'monolog_handlers' => [ 28 | function () { 29 | return new \Monolog\Handler\StreamHandler( 30 | __DIR__.'/private/logs/app.log', 31 | \Monolog\Logger::DEBUG 32 | ); 33 | }, 34 | ], 35 | ], 36 | ], 37 | 38 | There are many different handlers you can add on top of this stack 39 | (monolog_handlers array). Some of them are listed 40 | `here `__. 41 | -------------------------------------------------------------------------------- /docs/configuration/router.rst: -------------------------------------------------------------------------------- 1 | .. _RouterAnchor: 2 | 3 | ====== 4 | Router 5 | ====== 6 | 7 | .. index:: Router 8 | 9 | -------------- 10 | Router Service 11 | -------------- 12 | 13 | The Router service is the well-known 14 | `FastRoute `__ library. There is no 15 | need to change this service unless you’re extending the script. 16 | 17 | The router uses the unique query parameter ``?r=`` to pass route information 18 | to other application components. Because of this feature, this (single-page) 19 | application does not require rewrite rules in the .htaccess file, or similar modifications. 20 | 21 | Example routes: 22 | 23 | - ``http://example.com/?r=/some/route¶m1=val1¶m2=val2`` 24 | - ``http://example.com/?r=/user/{user_id}¶m1=val1`` 25 | 26 | ----------- 27 | Routes File 28 | ----------- 29 | 30 | .. index:: Routes file 31 | 32 | The Routes files are located in the ``config/`` folder. There are two main files 33 | that will configure routes: ``config/routes.config.php`` and 34 | ``config/routes.optional.config.php``. Each route is defined like so: 35 | 36 | :: 37 | 38 | [ 39 | 'route' => [ 40 | 'GET', '/download/{path_encoded}', '\Filebrowser\Controllers\DownloadController@download', 41 | ], 42 | 'roles' => [ 43 | 'guest', 'user', 'admin', 44 | ], 45 | 'permissions' => [ 46 | 'download', 47 | ], 48 | ], 49 | 50 | As you can see in this example, you can assign required user roles and 51 | permissions for each route. 52 | 53 | ----------- 54 | Controllers 55 | ----------- 56 | 57 | .. index:: Controllers 58 | 59 | Since FileBrowser is using an awesome dependency injection 60 | `container `__, you can type hint 61 | dependencies directly in the definition of a controller's action methods. 62 | 63 | You can also mix route parameters and dependencies in any order, like in 64 | this example: 65 | 66 | :: 67 | 68 | public function __construct(Config $config, Session $session, AuthInterface $auth, Filesystem $storage) 69 | { 70 | // ... 71 | } 72 | 73 | public function download($path_encoded, Request $request, Response $response, StreamedResponse $streamedResponse) 74 | { 75 | // ... 76 | } 77 | -------------------------------------------------------------------------------- /docs/configuration/security.rst: -------------------------------------------------------------------------------- 1 | .. _SecurityAnchor: 2 | 3 | ======== 4 | Security 5 | ======== 6 | 7 | .. index:: Security 8 | 9 | -------------------------------- 10 | Configuring the Security Service 11 | -------------------------------- 12 | 13 | .. index:: Security configuration 14 | 15 | A simple security service is included in the application by default. This 16 | service provides: 17 | 18 | - A basic session-based 19 | `CSRF `__ 20 | protection, 21 | - An IP allow list, 22 | - An IP deny list. 23 | 24 | :: 25 | 26 | 'Filebrowser\Services\Security\Security' => [ 27 | 'handler' => '\Filebrowser\Services\Security\Security', 28 | 'config' => [ 29 | 'csrf_protection' => true, 30 | 'csrf_key' => "123456", // randomize this 31 | 'ip_allowlist' => [], 32 | 'ip_denylist' => [ 33 | '172.16.1.2', 34 | '172.16.3.4', 35 | ], 36 | ], 37 | ], 38 | 39 | If you set the ``ip_allowlist`` option, then only users coming from the listed IP 40 | addresses will be able to use the application. 41 | -------------------------------------------------------------------------------- /docs/configuration/tmpfs.rst: -------------------------------------------------------------------------------- 1 | .. _TmpfsAnchor: 2 | 3 | ============================= 4 | Temporary File System Service 5 | ============================= 6 | 7 | .. index:: Temporary file system service 8 | 9 | This service is responsible for managing temporary files. TMP files are 10 | created: 11 | 12 | - When uploading files, chunks are stored in the TMP folder before 13 | merging and moving them to the final storage destination, 14 | - When creating and extracting archives (zip files), 15 | - When downloading multiple files, they are copied into the TMP folder 16 | before zipping. 17 | 18 | Tmp files are usually removed immediately after their use. For expired 19 | files, configurable garbage collection is used: 20 | 21 | :: 22 | 23 | 'Filebrowser\Services\Tmpfs\TmpfsInterface' => [ 24 | 'handler' => '\Filebrowser\Services\Tmpfs\Adapters\Tmpfs', 25 | 'config' => [ 26 | 'path' => __DIR__.'/private/tmp/', 27 | 'gc_probability_perc' => 10, 28 | 'gc_older_than' => 60 * 60 * 24 * 2, // 2 days 29 | ], 30 | ], 31 | 32 | .. note:: if you want to use this script as a stateless app or in any kind of multi-node environment, you must mount a single shared TMP folder for all the instances. You can solve this problem with `Amazon Elastic File System `__, or a similar approach. 33 | -------------------------------------------------------------------------------- /docs/configuration_basic.rst: -------------------------------------------------------------------------------- 1 | .. _ConfigurationAnchor: 2 | 3 | ============== 4 | Configuration 5 | ============== 6 | 7 | .. index:: Configuration 8 | 9 | ------------------- 10 | Basic configuration 11 | ------------------- 12 | 13 | .. index:: Configuration basics 14 | 15 | All services are set with fairly conservative defaults. For regular users, there 16 | is no need to change anything. The application should work out of the box. 17 | 18 | You can edit the ``configuration.php`` file in order to customize the application, by changing things 19 | like the logo, the title, the language settings, and the upload permissions. 20 | 21 | All other configuration files can be found in the ``config/`` folder. 22 | 23 | .. note:: If you make a mistake in any of the configuration files (forgot to close a quote?), the application will fail to load, and log an error. Please use the provided default ``configuration_sample.php`` file to restore the configuration to its initial state. 24 | 25 | :: 26 | 27 | 'frontend_config' => [ 28 | 'app_name' => 'FileBrowser', 29 | 'app_version' => APP_VERSION, 30 | 'language' => 'english', 31 | 'logo' => 'https://linuxforphp.com/img/logo.svg', 32 | 'upload_max_size' => 100 * 1024 * 1024, // 100MB 33 | 'upload_chunk_size' => 1 * 1024 * 1024, // 1MB 34 | 'upload_simultaneous' => 3, 35 | 'default_archive_name' => 'archive.zip', 36 | 'editable' => ['.txt', '.css', '.js', '.ts', '.html', '.php', '.json', '.ini', '.cnf', '.conf', '.env', '.monthly', '.weekly', '.daily', '.hourly', '.minute', '.htaccess'], 37 | 'date_format' => 'YY/MM/DD hh:mm:ss', // see: https://momentjs.com/docs/#/displaying/format/ 38 | 'guest_redirection' => '', // useful for external auth adapters 39 | 'search_simultaneous' => 5, 40 | 'filter_entries' => [], 41 | ], 42 | 43 | ------------------ 44 | Adding Custom HTML 45 | ------------------ 46 | 47 | .. index:: Configuration customizations 48 | 49 | .. index:: Adding a MOTD 50 | 51 | .. index:: Page customizations 52 | 53 | You can add additional html to the head and body like this: 54 | 55 | :: 56 | 57 | 'Filebrowser\Services\View\ViewInterface' => [ 58 | 'handler' => '\Filebrowser\Services\View\Adapters\Vuejs', 59 | 'config' => [ 60 | 'add_to_head' => '', 61 | 'add_to_body' => '', 62 | ], 63 | ], 64 | 65 | ----------------- 66 | Tweaking the Look 67 | ----------------- 68 | 69 | .. index:: Change the look 70 | 71 | .. index:: Front end changes 72 | 73 | To change default color scheme and other options, edit 74 | ``frontend/App.vue`` When you’re done, recompile with ``npm run build`` 75 | like described in the :ref:`development` section. 76 | 77 | :: 78 | 79 | // Primary color 80 | $primary: #34B891; 81 | $primary-invert: findColorInvert($primary); 82 | 83 | $colors: ( 84 | "primary": ($primary, $primary-invert), 85 | "info": ($info, $info-invert), 86 | "success": ($success, $success-invert), 87 | "warning": ($warning, $warning-invert), 88 | "danger": ($danger, $danger-invert), 89 | ); 90 | 91 | // Links 92 | $link: $primary; 93 | $link-invert: $primary-invert; 94 | $link-focus-border: $primary; 95 | 96 | // Disable the widescreen breakpoint 97 | $widescreen-enabled: false; 98 | 99 | // Disable the fullhd breakpoint 100 | $fullhd-enabled: false; 101 | -------------------------------------------------------------------------------- /docs/development.rst: -------------------------------------------------------------------------------- 1 | .. _DevelopmentAnchor: 2 | 3 | =========== 4 | Development 5 | =========== 6 | 7 | .. index:: Development 8 | 9 | .. _development: 10 | 11 | ------------------------------------- 12 | Project Setup for Development (Linux) 13 | ------------------------------------- 14 | 15 | .. index:: Development setup 16 | 17 | You must have ``git``, ``php``, ``npm``, and ``composer`` installed. 18 | 19 | If you have `Docker` and `Linux for Composer` (https://github.com/linuxforphp/linuxforcomposer) on your computer, you can start the container with the following command: 20 | 21 | :: 22 | 23 | git clone https://github.com/linuxforphp/filebrowser.git 24 | cd filebrowser 25 | composer install --ignore-platform-reqs 26 | vendor/bin/linuxforcomposer docker:run start 27 | 28 | 29 | When you are ready to stop the container, enter the following command: 30 | 31 | :: 32 | 33 | vendor/bin/linuxforcomposer docker:run stop-force 34 | 35 | Otherwise, you can install the application manually, using the following commands: 36 | 37 | :: 38 | 39 | git clone https://github.com/linuxforphp/filebrowser.git 40 | cd filebrowser 41 | cp configuration_sample.php configuration.php 42 | chmod -R 775 private/ 43 | chmod -R 775 repository/ 44 | composer install --ignore-platform-reqs 45 | npm install 46 | npm run build 47 | 48 | ------------------------ 49 | Compiles and Hot Reloads 50 | ------------------------ 51 | 52 | .. index:: Compilation 53 | 54 | The following command will launch the back end and the front end of the application 55 | on ports 8081 and 8080 respectively: 56 | 57 | :: 58 | 59 | npm run serve 60 | 61 | Once everything is ready, please visit: ``http://localhost:8080`` 62 | 63 | ------------------------------- 64 | Running Tests & Static Analysis 65 | ------------------------------- 66 | 67 | .. index:: Testing 68 | 69 | Testing requires xdebug, php-zip and sqlite php extensions. 70 | 71 | :: 72 | 73 | vendor/bin/phpunit 74 | vendor/bin/phpstan analyse ./backend 75 | npm run lint 76 | npm run e2e 77 | 78 | ---------- 79 | Deployment 80 | ---------- 81 | 82 | .. index:: Deployment 83 | 84 | Set the website document root to the ``/dist`` directory. This is also known 85 | as the ‘public’ folder. 86 | 87 | NOTE: For security reasons, the ``/dist`` folder is the ONLY folder you want to be 88 | exposed to the Web. Everything else should be outside of your web 89 | root. This way, people won't be able to access any of your important files through 90 | the Web browser. 91 | -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/docs/images/logo.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. _IndexAnchor: 2 | 3 | Welcome to the FileBrowser Documentation 4 | ========================================= 5 | .. image:: /images/logo.png 6 | 7 | `FileBrowser Home Page `_ 8 | 9 | .. toctree:: 10 | :maxdepth: 3 11 | :glob: 12 | 13 | introduction 14 | installation 15 | accounts 16 | configuration_basic 17 | configuration/* 18 | translations/* 19 | development 20 | license 21 | 22 | 23 | Indices and tables 24 | ================== 25 | 26 | * :ref:`genindex` 27 | * :ref:`search` -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. _InstallationAnchor: 2 | 3 | ============ 4 | Installation 5 | ============ 6 | 7 | .. index:: Installation 8 | 9 | -------------------- 10 | Minimum Requirements 11 | -------------------- 12 | 13 | .. index:: Requirements 14 | 15 | - FileBrowser 8.1.0: PHP 8.0 - 8.2 (with php-zip extension) 16 | - FileBrowser 8.0.3: PHP 7.2 - 7.4 (with php-zip extension) 17 | 18 | ----------------------------- 19 | Download a Pre-Compiled Build 20 | ----------------------------- 21 | 22 | .. index:: Pre-compiled build 23 | 24 | The pre-compiled builds are created for non-developers. With this version of the FileBrowser, 25 | the front end code (HTML, CSS and Javascript) is already pre-compiled for you, and the source 26 | code is removed, so that the final archive file contains only what is required 27 | to run the application on your server. 28 | 29 | - Download the `latest 30 | release `__, 31 | - Unzip the files, and upload them to your PHP server, 32 | - Make sure your web server can read and write to the 33 | ``filebrowser/repository/`` and ``filebrowser/private/`` folders, 34 | - Set the website document root to the ``filebrowser/dist/`` directory 35 | (this is also known as ‘public’ folder), 36 | - Visit the web page, and if something goes wrong, please check 37 | ``filebrowser/private/logs/app.log``, 38 | - Login with default credentials ``admin/admin123``, 39 | - Change default admin’s password. 40 | 41 | NOTE: For security reasons, the ``/dist`` folder is the ONLY folder you want to be 42 | exposed to the Web. Everything else should be outside of your web 43 | root. This way, people won't be able to access any of your important files through 44 | the Web browser. 45 | 46 | Install on fresh Ubuntu 18.04 or Debian 10.3 47 | -------------------------------------------- 48 | 49 | .. index:: Ubuntu (installation) 50 | 51 | .. index:: Debian (installation) 52 | 53 | On a new server, login as root and enter 54 | this into the shell: 55 | 56 | :: 57 | 58 | apt update 59 | apt install -y wget unzip php apache2 libapache2-mod-php php-zip 60 | 61 | cd /var/www/ 62 | wget -O filebrowser_latest.zip https://filebrowser.linuxforphp.net/files/filebrowser_latest.zip 63 | unzip filebrowser_latest.zip && rm filebrowser_latest.zip 64 | 65 | chown -R www-data:www-data filebrowser/ 66 | chmod -R 775 filebrowser/ 67 | 68 | echo " 69 | 70 | DocumentRoot /var/www/filebrowser/dist 71 | 72 | " >> /etc/apache2/sites-available/filebrowser.conf 73 | 74 | a2dissite 000-default.conf 75 | a2ensite filebrowser.conf 76 | systemctl restart apache2 77 | 78 | exit 79 | 80 | Open your browser and go to http://your_server_ip_address 81 | 82 | ------- 83 | Upgrade 84 | ------- 85 | 86 | .. index:: Upgrade 87 | 88 | Since version 7 is completely rewritten from scratch, there is no clear 89 | upgrade path from older versions. 90 | 91 | If you have an older version of FileBrowser please backup everything and 92 | install the script again. 93 | 94 | Upgrade instructions for non-developers: 95 | 96 | - Backup everything, 97 | - Download the latest version, 98 | - Replace all files and folders except ``repository/`` and ``private/``. 99 | 100 | To discover which version of the FileBrowser you are running, 101 | please look for ``APP_VERSION`` inside ``dist/index.php`` file 102 | -------------------------------------------------------------------------------- /docs/introduction.rst: -------------------------------------------------------------------------------- 1 | .. _IntroductionAnchor: 2 | 3 | ====================== 4 | What is FileBrowser? 5 | ====================== 6 | 7 | .. index:: FileBrowser 8 | 9 | `FileBrowser `__ is a free, 10 | `open-source `__, 11 | self-hosted web application for managing files and folders. 12 | 13 | You can manage files inside your local repository folder (on your 14 | server’s hard drive) or connect to other storage adapters (see below). 15 | 16 | FileBrowser has multi-user support, so you can have administrators and other 17 | users managing their files with different access permissions, roles and 18 | home folders. 19 | 20 | All basic file operations are supported: copy, move, rename, create, 21 | delete, zip, unzip, download, upload. 22 | 23 | If allowed, users can download multiple files or folders at once. 24 | 25 | File upload supports drag&drop, progress bar, pause and resume. Upload 26 | is chunked so you should be able to upload large files regardless of 27 | your server’s configuration. 28 | 29 | ---------------- 30 | Features & Goals 31 | ---------------- 32 | 33 | - Multiple storage adapters (Local, FTP, Amazon S3, Dropbox, DO Spaces, 34 | Azure Blob and many others via 35 | `Flysystem `__), 36 | - Multiple authentication adapters with roles and permissions (store users in 37 | a json file, database, or use WordPress), 38 | - Multiple session adapters (native file, Pdo, Redis, MongoDB, 39 | Memcached, and others via 40 | `Symfony `__), 41 | - Single page front-end (built with 42 | `Vue.js `__, 43 | `Bulma `__ and 44 | `Buefy `__), 45 | - Chunked uploads (built with 46 | `Resumable.js `__), 47 | - Zip and bulk download support, 48 | - Highly extensible, decoupled and tested code, 49 | - No database required. 50 | 51 | -------------------------- 52 | Why Open Source on GitHub? 53 | -------------------------- 54 | 55 | There are several reasons why we switched to the open source model. 56 | 57 | Basically, we wanted to increase: 58 | 59 | - Code quality by bringing more developers to the project, 60 | - Code stability, 61 | - Security, 62 | - Project lifetime. 63 | 64 | At the end, the more people can see and test some code, the more 65 | likely any flaws will be caught and fixed quickly. 66 | 67 | ----------------- 68 | Show Your Support 69 | ----------------- 70 | 71 | - Please star this repository on 72 | `GitHub `__ if 73 | this project helped you! 74 | 75 | ------- 76 | License 77 | ------- 78 | 79 | Copyright 2021, `Foreach Code Factory `__. 80 | Copyright 2018-2021, `Milos Stojanovic `__. 81 | 82 | This project is Apache-2.0 licensed. 83 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx == 5.3.0 2 | urllib3 == 1.26.15 -------------------------------------------------------------------------------- /frontend/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | 19 | 94 | 95 | -------------------------------------------------------------------------------- /frontend/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/frontend/assets/logo.png -------------------------------------------------------------------------------- /frontend/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import store from './store' 5 | import Buefy from 'buefy' 6 | import shared from './mixins/shared' 7 | import axios from 'axios' 8 | import api from './api/api' 9 | import VueLazyload from 'vue-lazyload' 10 | import '@fortawesome/fontawesome-free/css/all.css' 11 | import '@fortawesome/fontawesome-free/css/fontawesome.css' 12 | 13 | //TODO: import './registerServiceWorker' 14 | 15 | Vue.config.productionTip = false 16 | 17 | /* eslint-disable-next-line */ 18 | Vue.config.baseURL = process.env.VUE_APP_API_ENDPOINT ? process.env.VUE_APP_API_ENDPOINT : window.location.origin+window.location.pathname+'?r=' 19 | 20 | axios.defaults.withCredentials = true 21 | axios.defaults.baseURL = Vue.config.baseURL 22 | 23 | axios.defaults.headers['Content-Type'] = 'application/json' 24 | 25 | Vue.use(Buefy, { 26 | defaultIconPack: 'fas', 27 | }) 28 | 29 | Vue.use(VueLazyload, { 30 | preLoad: 1.3, 31 | }) 32 | 33 | 34 | Vue.mixin(shared) 35 | 36 | new Vue({ 37 | router, 38 | store, 39 | created: function() { 40 | 41 | api.getConfig() 42 | .then(ret => { 43 | this.$store.commit('setConfig', ret.data.data) 44 | api.getUser() 45 | .then((user) => { 46 | this.$store.commit('initialize') 47 | this.$store.commit('setUser', user) 48 | this.$router.push('/').catch(() => {}) 49 | }) 50 | .catch(() => { 51 | this.$notification.open({ 52 | message: this.lang('Something went wrong'), 53 | type: 'is-danger', 54 | queue: false, 55 | indefinite: true, 56 | }) 57 | }) 58 | }) 59 | .catch(() => { 60 | this.$notification.open({ 61 | message: this.lang('Something went wrong'), 62 | type: 'is-danger', 63 | queue: false, 64 | indefinite: true, 65 | }) 66 | }) 67 | }, 68 | render: h => h(App), 69 | }).$mount('#app') 70 | -------------------------------------------------------------------------------- /frontend/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | import { register } from 'register-service-worker' 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready () { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB' 11 | ) 12 | }, 13 | registered () { 14 | console.log('Service worker has been registered.') 15 | }, 16 | cached () { 17 | console.log('Content has been cached for offline use.') 18 | }, 19 | updatefound () { 20 | console.log('New content is downloading.') 21 | }, 22 | updated () { 23 | console.log('New content is available; please refresh.') 24 | }, 25 | offline () { 26 | console.log('No internet connection found. App is running in offline mode.') 27 | }, 28 | error (error) { 29 | console.error('Error during service worker registration:', error) 30 | } 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /frontend/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Browser from './views/Browser.vue' 4 | import Users from './views/Users.vue' 5 | import Login from './views/Login.vue' 6 | import store from './store' 7 | 8 | Vue.use(Router) 9 | 10 | export default new Router({ 11 | mode: 'hash', 12 | routes: [ 13 | { 14 | path: '/', 15 | name: 'browser', 16 | component: Browser, 17 | }, 18 | { 19 | path: '/login', 20 | name: 'login', 21 | component: Login, 22 | }, 23 | { 24 | path: '/users', 25 | name: 'users', 26 | component: Users, 27 | beforeEnter: (to, from, next) => { 28 | if (store.state.user.role == 'admin') { 29 | next() 30 | } 31 | }, 32 | }, 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /frontend/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import shared from './mixins/shared' 4 | import _ from 'lodash' 5 | 6 | Vue.use(Vuex) 7 | 8 | export default new Vuex.Store({ 9 | state: { 10 | initialized: false, 11 | config: [], 12 | user: { 13 | role: 'guest', 14 | permissions: [], 15 | name: '', 16 | username: '' 17 | }, 18 | cwd: { 19 | location: '/', 20 | content: [], 21 | }, 22 | tree: {}, 23 | }, 24 | getters: { 25 | hasPermissions: (state) => (permissions) => { 26 | if (_.isArray(permissions)) { 27 | return _.intersection(state.user.permissions, permissions).length == permissions.length 28 | } 29 | return _.find(state.user.permissions, p => p == permissions) ? true : false 30 | } 31 | }, 32 | mutations: { 33 | initialize(state) { 34 | state.initialized = true 35 | this.commit('resetCwd') 36 | this.commit('resetTree') 37 | this.commit('destroyUser') 38 | }, 39 | resetCwd(state) { 40 | state.cwd = { 41 | location: '/', 42 | content: [], 43 | } 44 | }, 45 | resetTree(state) { 46 | state.tree = { 47 | path: '/', 48 | name: shared.methods.lang('Home'), 49 | children: [], 50 | } 51 | }, 52 | setConfig(state, data) { 53 | state.config = data 54 | }, 55 | setUser(state, data) { 56 | state.user = data 57 | }, 58 | destroyUser(state) { 59 | state.user = { 60 | role: 'guest', 61 | permissions: [], 62 | name: '', 63 | username: '', 64 | } 65 | }, 66 | setCwd(state, data) { 67 | 68 | state.cwd.location = data.location 69 | state.cwd.content = [] 70 | 71 | _.forEach(_.sortBy(data.content, [function(o) { return _.toLower(o.type) }]), (o) => { 72 | state.cwd.content.push(o) 73 | }) 74 | 75 | }, 76 | updateTreeNode(state, data) { 77 | let traverse = function (object) { 78 | for (let property in object) { 79 | if (object.hasOwnProperty(property)) { 80 | if (property === 'path' && object[property] === data.path) { 81 | Object.assign(object, { 82 | path: data.path, 83 | children: data.children, 84 | }) 85 | return 86 | } 87 | if (typeof object[property] === 'object') { 88 | traverse(object[property]) 89 | } 90 | } 91 | } 92 | } 93 | traverse(state.tree) 94 | }, 95 | }, 96 | actions: { 97 | } 98 | }) 99 | -------------------------------------------------------------------------------- /frontend/translations/bulgarian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Избрани: {0} от {1}', 3 | 'Uploading files': 'Качване {0}% от {1}', 4 | 'File size error': '{0} е твърде голям, моля, качете файлове по-малко от {1}', 5 | 'Upload failed': '{0} Грещка при качване', 6 | 'Per page': '{0} На страница', 7 | 'Folder': 'Папка', 8 | 'Login failed, please try again': 'Грешка при вписване, опитайте отново', 9 | 'Already logged in': 'Вече сте влезли.', 10 | 'Please enter username and password': 'Моля въведете потребителско име и парола.', 11 | 'Not Found': 'Не е намерено', 12 | 'Not Allowed': 'Не е позволено', 13 | 'Please log in': 'Моля впишете се', 14 | 'Unknown error': 'Неизвестна грешка', 15 | 'Add files': 'Добаве файлове', 16 | 'New': 'Ново', 17 | 'New name': 'Ново име', 18 | 'Username': 'Потребителско име', 19 | 'Password': 'Парола', 20 | 'Login': 'Вписване', 21 | 'Logout': 'Изход', 22 | 'Profile': 'Профил', 23 | 'No pagination': 'Няма пагинация', 24 | 'Time': 'Дата', 25 | 'Name': 'Име', 26 | 'Size': 'Размер', 27 | 'Home': 'Начало', 28 | 'Copy': 'Копиране', 29 | 'Move': 'Изрежи', 30 | 'Rename': 'Преименуване', 31 | 'Required': 'Моля, попълнете това поле', 32 | 'Zip': 'Архив', 33 | 'Batch Download': 'Пакетно изтегляне', 34 | 'Unzip': 'Разархивирай', 35 | 'Delete': 'Изтриване', 36 | 'Download': 'Изтегляне', 37 | 'Copy link': 'Копирай линк', 38 | 'Done': 'Завършено', 39 | 'File': 'Файл', 40 | 'Drop files to upload': 'Пускане на файлове за качване', 41 | 'Close': 'Затвори', 42 | 'Select Folder': 'Избери папка', 43 | 'Users': 'Потребител', 44 | 'Files': 'Файлове', 45 | 'Role': 'Права', 46 | 'Cancel': 'Отказ', 47 | 'Paused': 'Пауза', 48 | 'Confirm': 'Потвърждение', 49 | 'Create': 'Създай', 50 | 'User': 'Потребител', 51 | 'Admin': 'Администратор', 52 | 'Save': 'Запази', 53 | 'Read': 'Чете', 54 | 'Write': 'Записва', 55 | 'Upload': 'Качи', 56 | 'Permissions': 'Разрешения', 57 | 'Homedir': 'Главна директория', 58 | 'Leave blank for no change': 'Оставете празно, за да няма промяна', 59 | 'Are you sure you want to do this?': 'Сигурни ли сте, че искате да направите това?', 60 | 'Are you sure you want to allow access to everyone?': 'Сигурни ли сте, че искате да разрешите достъп на всички?', 61 | 'Are you sure you want to stop all uploads?': 'Сигурни ли сте, че искате да спрете всички качвания?', 62 | 'Something went wrong': 'Нещо се обърка', 63 | 'Invalid directory': 'Невалидна директория', 64 | 'This field is required': 'Това поле е задължително', 65 | 'Username already taken': 'Потребителско име вече е заето', 66 | 'User not found': 'Потребителя не е намерен', 67 | 'Old password': 'Стара парола', 68 | 'New password': 'Нова парола', 69 | 'Wrong password': 'Грешна парола', 70 | 'Updated': 'Обновено', 71 | 'Deleted': 'Изтрити', 72 | 'Your file is ready': 'Вашия файл е готов', 73 | 'View': 'Преглед', 74 | 'Search': 'Търси', 75 | 'Download permission': 'Свали', 76 | 'Guest': 'Гост', 77 | 'Show hidden': 'Показване на скрито', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/chinese.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': '已选择: {1} 个文件中的 {0} 个', 3 | 'Uploading files': '已上传 {1} 中的 {0}%', 4 | 'File size error': '{0} 尺寸过大, 您最大只可上传 {1}', 5 | 'Upload failed': '{0} 上传失败', 6 | 'Per page': '每页 {0} 个', 7 | 'Folder': '文件夹', 8 | 'Login failed, please try again': '登录失败, 请重试', 9 | 'Already logged in': '已登录。', 10 | 'Please enter username and password': '请输入用户名和密码。', 11 | 'Not Found': '未找到', 12 | 'Not Allowed': '不允许', 13 | 'Please log in': '请登录', 14 | 'Unknown error': '未知错误', 15 | 'Add files': '上传文件', 16 | 'New': '新建', 17 | 'New name': '新名称', 18 | 'Username': '用户名', 19 | 'Password': '密码', 20 | 'Login': '登录', 21 | 'Logout': '退出', 22 | 'Profile': '更改信息', 23 | 'No pagination': '不分页', 24 | 'Time': '时间', 25 | 'Name': '名称', 26 | 'Size': '大小', 27 | 'Home': '主页', 28 | 'Copy': '复制', 29 | 'Move': '移动', 30 | 'Rename': '重命名', 31 | 'Required': '请填写此字段', 32 | 'Zip': '压缩', 33 | 'Batch Download': '批量下载', 34 | 'Unzip': '解压缩', 35 | 'Delete': '删除', 36 | 'Download': '下载', 37 | 'Copy link': '复制链接', 38 | 'Done': '完成', 39 | 'File': '文件', 40 | 'Drop files to upload': '拖放文件即可上传', 41 | 'Close': '关闭', 42 | 'Select Folder': '选择文件夹', 43 | 'Users': '用户', 44 | 'Files': '文件', 45 | 'Role': '角色', 46 | 'Cancel': '取消', 47 | 'Paused': '暂停', 48 | 'Confirm': '确认', 49 | 'Create': '创建', 50 | 'User': '用户', 51 | 'Admin': '管理员', 52 | 'Save': '保存', 53 | 'Read': '读取', 54 | 'Write': '写入', 55 | 'Upload': '上传', 56 | 'Permissions': '权限', 57 | 'Homedir': '根目录', 58 | 'Leave blank for no change': '留空表示不更改', 59 | 'Are you sure you want to do this?': '你确定要干这事?', 60 | 'Are you sure you want to allow access to everyone?': '你确定要让任何人随意访问?', 61 | 'Are you sure you want to stop all uploads?': '你确定要停止所有上传任务?', 62 | 'Something went wrong': '有啥坏了', 63 | 'Invalid directory': '目录无效', 64 | 'This field is required': '必须填写这个字段', 65 | 'Username already taken': '用户名已被注册', 66 | 'User not found': '未找到用户', 67 | 'Old password': '旧密码', 68 | 'New password': '新密码', 69 | 'Wrong password': '密码错误', 70 | 'Updated': '已更新', 71 | 'Deleted': '已删除', 72 | 'Your file is ready': '您的文件已备妥', 73 | 'View': '查看', 74 | 'Search': '搜索', 75 | 'Download permission': '下载', 76 | 'Guest': '游客', 77 | 'Show hidden': '显示隐藏', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/czech.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Vybrané: {0} z {1}', 3 | 'Uploading files': 'Nahrávám {0}% z {1}', 4 | 'File size error': '{0} je příliš velký, nahrávejte soubory menší jak {1}', 5 | 'Upload failed': '{0} se nepodařilo nahrát', 6 | 'Per page': '{0} na stránku', 7 | 'Folder': 'Adresář', 8 | 'Login failed, please try again': 'Přihlášení neúspěšné, zkuste to znova', 9 | 'Already logged in': 'Už jste přihlášený.', 10 | 'Please enter username and password': 'Zadejte přihlašovací jméno a heslo.', 11 | 'Not Found': 'Nenalezeno', 12 | 'Not Allowed': 'Nepovolené', 13 | 'Please log in': 'Přihlaste se', 14 | 'Unknown error': 'Neznámá chyba', 15 | 'Add files': 'Nahrát soubory', 16 | 'New': 'Nový', 17 | 'New name': 'Nové jméno', 18 | 'Username': 'Přihlašovací jméno', 19 | 'Password': 'Heslo', 20 | 'Login': 'Přihlásit se', 21 | 'Logout': 'Odhlásit se', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Bez stránkování', 24 | 'Time': 'Čas', 25 | 'Name': 'Jméno', 26 | 'Size': 'Velikost', 27 | 'Home': 'Hlavní adresář', 28 | 'Copy': 'Kopírovat', 29 | 'Move': 'Přesunout', 30 | 'Rename': 'Přejmenovat', 31 | 'Required': 'Vyplňte toto pole', 32 | 'Zip': 'Archivovat do zip', 33 | 'Batch Download': 'Hromadné stahování', 34 | 'Unzip': 'Rozbalit zip archív', 35 | 'Delete': 'Smazat', 36 | 'Download': 'Stáhnout', 37 | 'Copy link': 'Zkopírovat odkaz', 38 | 'Done': 'Hotovo', 39 | 'File': 'Soubor', 40 | 'Drop files to upload': 'Pro nahrání přesuňte soubory sem', 41 | 'Close': 'Zavřít', 42 | 'Select Folder': 'Vyberte adresář', 43 | 'Users': 'Uživatelé', 44 | 'Files': 'Soubory', 45 | 'Role': 'Typ účtu', 46 | 'Cancel': 'Zrušit', 47 | 'Paused': 'Pozastavené', 48 | 'Confirm': 'Potvrdit', 49 | 'Create': 'Vytvořit', 50 | 'User': 'Uživatel', 51 | 'Admin': 'Admin', 52 | 'Save': 'Uložit', 53 | 'Read': 'Čtení', 54 | 'Write': 'Zapisování', 55 | 'Upload': 'Nahrávání', 56 | 'Permissions': 'Oprávnění', 57 | 'Homedir': 'Hlavní adresář', 58 | 'Leave blank for no change': 'Pokud nechcete změnit, nechejte prázdné', 59 | 'Are you sure you want to do this?': 'Skutečně to chcete udělat?', 60 | 'Are you sure you want to allow access to everyone?': 'Skutečně chcete povolit přístup bez hesla?', 61 | 'Are you sure you want to stop all uploads?': 'Skutečně chcete zastavit všechna nahrávání?', 62 | 'Something went wrong': 'Něco se pokazilo', 63 | 'Invalid directory': 'Neplatný adresář', 64 | 'This field is required': 'Toto pole je povinné', 65 | 'Username already taken': 'Toto přihlašovací jméno se už používá', 66 | 'User not found': 'Uživatel se nenašel', 67 | 'Old password': 'Staré heslo', 68 | 'New password': 'Nové heslo', 69 | 'Wrong password': 'Špatné heslo', 70 | 'Updated': 'Aktualizované', 71 | 'Deleted': 'Smazané', 72 | 'Your file is ready': 'Váš soubor je připravený', 73 | 'View': 'Zobrazit', 74 | 'Search': 'Vyhledávání', 75 | 'Download permission': 'Stahování', 76 | 'Guest': 'Host', 77 | 'Show hidden': 'Zobrazit skryté', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/dutch.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Geselecteerd: {0} van {1}', 3 | 'Uploading files': 'Geüpload: {0}% van {1}', 4 | 'File size error': '{0} is te groot, maximale grootte is {1}', 5 | 'Upload failed': '{0} upload mislukt', 6 | 'Per page': '{0} per pagina', 7 | 'Folder': 'Map', 8 | 'Login failed, please try again': 'Login mislukt, probeer het nog eens...', 9 | 'Already logged in': 'U bent al ingelogd...', 10 | 'Please enter username and password': 'Geef gebruikersnaam en wachtwoord', 11 | 'Not Found': 'Niet gevonden', 12 | 'Not Allowed': 'Niet toegestaan', 13 | 'Please log in': 'Log eerst in', 14 | 'Unknown error': 'Onbekende fout', 15 | 'Add files': 'Bestanden toevoegen', 16 | 'New': 'Nieuw', 17 | 'New name': 'Nieuwe naam', 18 | 'Username': 'Gebruikersnaam', 19 | 'Password': 'Wachtwoord', 20 | 'Login': 'Log in', 21 | 'Logout': 'Log uit', 22 | 'Profile': 'Profiel', 23 | 'No pagination': 'Geen onderverdeling in pagina\'s', 24 | 'Time': 'Tijd', 25 | 'Name': 'Naam', 26 | 'Size': 'Grootte', 27 | 'Home': 'Thuismap', 28 | 'Copy': 'Kopieer', 29 | 'Move': 'Verplaats', 30 | 'Rename': 'Hernoem', 31 | 'Required': 'Vereist veld', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Groepsdownload', 34 | 'Unzip': 'Uitpakken', 35 | 'Delete': 'Verwijder', 36 | 'Download': 'Download', 37 | 'Copy link': 'Kopieer link', 38 | 'Done': 'Klaar', 39 | 'File': 'Bestand', 40 | 'Drop files to upload': 'Sleep bestanden hierheen om ze te uploaden', 41 | 'Close': 'Sluiten', 42 | 'Select Folder': 'Selecteer Map', 43 | 'Users': 'Gebruikers', 44 | 'Files': 'Bestanden', 45 | 'Role': 'Rol', 46 | 'Cancel': 'Afbreken', 47 | 'Paused': 'Gepauseerd', 48 | 'Confirm': 'Bevestig', 49 | 'Create': 'Nieuw', 50 | 'User': 'Gebruiker', 51 | 'Admin': 'Beheerder', 52 | 'Save': 'Opslaan', 53 | 'Read': 'Lezen', 54 | 'Write': 'Schrijven', 55 | 'Upload': 'Uploaden', 56 | 'Permissions': 'Permissies', 57 | 'Homedir': 'Thuismap', 58 | 'Leave blank for no change': 'Laat leeg om ongewijzigd te laten', 59 | 'Are you sure you want to do this?': 'Weet u het zeker?', 60 | 'Are you sure you want to allow access to everyone?': 'Weet u zeker dat u iedereen toegang wil geven?', 61 | 'Are you sure you want to stop all uploads?': 'Weet u zeker dat u alle uploads wil stoppen?', 62 | 'Something went wrong': 'Er is iets foutgegaan', 63 | 'Invalid directory': 'Ongeldige map', 64 | 'This field is required': 'This field is required', 65 | 'Username already taken': 'Naam is al in gebruik', 66 | 'User not found': 'Gebruiker niet gevonden', 67 | 'Old password': 'Oud wachtwoord', 68 | 'New password': 'Nieuw wachtwoord', 69 | 'Wrong password': 'Fout wachtwoord', 70 | 'Updated': 'Aangepast', 71 | 'Deleted': 'Verwijderd', 72 | 'Your file is ready': 'Uw bestand is verwerkt', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Download', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Verborgen weergeven', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/english.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Selected: {0} of {1}', 3 | 'Uploading files': 'Uploading {0}% of {1}', 4 | 'File size error': '{0} is too large, please upload files less than {1}', 5 | 'Upload failed': '{0} failed to upload', 6 | 'Per page': '{0} Per Page', 7 | 'Folder': 'Folder', 8 | 'Login failed, please try again': 'Login failed, please try again', 9 | 'Already logged in': 'Already logged in.', 10 | 'Please enter username and password': 'Please enter username and password.', 11 | 'Not Found': 'Not Found', 12 | 'Not Allowed': 'Not Allowed', 13 | 'Please log in': 'Please log in', 14 | 'Unknown error': 'Unknown error', 15 | 'Add files': 'Add files', 16 | 'New': 'New', 17 | 'New name': 'New name', 18 | 'Username': 'Username', 19 | 'Password': 'Password', 20 | 'Login': 'Log in', 21 | 'Logout': 'Log out', 22 | 'Profile': 'Profile', 23 | 'No pagination': 'No pagination', 24 | 'Time': 'Time', 25 | 'Name': 'Name', 26 | 'Size': 'Size', 27 | 'Home': 'Home', 28 | 'Copy': 'Copy', 29 | 'Move': 'Move', 30 | 'Rename': 'Rename', 31 | 'Required': 'Please fill out this field', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Batch Download', 34 | 'Unzip': 'Unzip', 35 | 'Delete': 'Delete', 36 | 'Download': 'Download', 37 | 'Copy link': 'Copy link', 38 | 'Done': 'Done', 39 | 'File': 'File', 40 | 'Drop files to upload': 'Drop files to upload', 41 | 'Close': 'Close', 42 | 'Select Folder': 'Select Folder', 43 | 'Users': 'Users', 44 | 'Files': 'Files', 45 | 'Role': 'Role', 46 | 'Cancel': 'Cancel', 47 | 'Paused': 'Paused', 48 | 'Confirm': 'Confirm', 49 | 'Create': 'Create', 50 | 'User': 'User', 51 | 'Admin': 'Admin', 52 | 'Save': 'Save', 53 | 'Read': 'Read', 54 | 'Write': 'Write', 55 | 'Upload': 'Upload', 56 | 'Permissions': 'Permissions', 57 | 'Homedir': 'Home Folder', 58 | 'Leave blank for no change': 'Leave blank for no change', 59 | 'Are you sure you want to do this?': 'Are you sure you want to do this?', 60 | 'Are you sure you want to allow access to everyone?': 'Are you sure you want to allow access to everyone?', 61 | 'Are you sure you want to stop all uploads?': 'Are you sure you want to stop all uploads?', 62 | 'Something went wrong': 'Something went wrong', 63 | 'Invalid directory': 'Invalid directory', 64 | 'This field is required': 'This field is required', 65 | 'Username already taken': 'Username already taken', 66 | 'User not found': 'User not found', 67 | 'Old password': 'Old password', 68 | 'New password': 'New password', 69 | 'Wrong password': 'Wrong password', 70 | 'Updated': 'Updated', 71 | 'Deleted': 'Deleted', 72 | 'Your file is ready': 'Your file is ready', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Download', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Show hidden', 78 | 'Large archive': 'Large archive file. The file will be ready soon. Please refresh the page in a few minutes...' 79 | } 80 | 81 | export default data 82 | 83 | -------------------------------------------------------------------------------- /frontend/translations/french.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Selectionné : {0} sur {1}', 3 | 'Uploading files': 'Upload {0}% sur {1}', 4 | 'File size error': '{0} est trop volumineux, merci d\'uploader des fichiers inférieurs à {1}', 5 | 'Upload failed': '{0} échec(s) d\'envoi', 6 | 'Per page': '{0} par page', 7 | 'Folder': 'Dossier', 8 | 'Login failed, please try again': 'Identification échoué, veuillez réessayer...', 9 | 'Already logged in': 'Vous êtes déjà connecté.', 10 | 'Please enter username and password': 'Saisissez votre nom d\'utilisateur et votre mot de passe.', 11 | 'Not Found': 'Introuvable', 12 | 'Not Allowed': 'Non autorisé', 13 | 'Please log in': 'Merci de vous connecter', 14 | 'Unknown error': 'Erreur inconnue', 15 | 'Add files': 'Ajout de fichier', 16 | 'New': 'Nouveau', 17 | 'New name': 'Nouveau nom', 18 | 'Username': 'Nom d\'utilisateur', 19 | 'Password': 'Mot de passe', 20 | 'Login': 'Connexion', 21 | 'Logout': 'Déconnexion', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Pas de pagination', 24 | 'Time': 'Date', 25 | 'Name': 'Nom', 26 | 'Size': 'Taille', 27 | 'Home': 'Accueil', 28 | 'Copy': 'Copier', 29 | 'Move': 'Déplacer', 30 | 'Rename': 'Renommer', 31 | 'Required': 'Merci de remplir ce champ', 32 | 'Zip': 'Compresser', 33 | 'Batch Download': 'Télécharger par lot', 34 | 'Unzip': 'Décompresser', 35 | 'Delete': 'Supprimer', 36 | 'Download': 'Télécharger', 37 | 'Copy link': 'Copier le lien', 38 | 'Done': 'Fait', 39 | 'File': 'Fichier', 40 | 'Drop files to upload': 'Glisser votre fichier pour l\'uploader', 41 | 'Close': 'Fermer', 42 | 'Select Folder': 'Selectionner le dossier', 43 | 'Users': 'Utilisateur', 44 | 'Files': 'Fichiers', 45 | 'Role': 'Rôle', 46 | 'Cancel': 'Annuler', 47 | 'Paused': 'En pause', 48 | 'Confirm': 'Confirmer', 49 | 'Create': 'Créer', 50 | 'User': 'Utilisateur', 51 | 'Admin': 'Administrateur', 52 | 'Save': 'Enregistrer', 53 | 'Read': 'Lire', 54 | 'Write': 'Écrire', 55 | 'Upload': 'Uploader', 56 | 'Permissions': 'Permissions', 57 | 'Homedir': 'Dossier principal', 58 | 'Leave blank for no change': 'Laisser vide si pas de modification', 59 | 'Are you sure you want to do this?': 'Êtes-vous sûr de vouloir faire ceci ?', 60 | 'Are you sure you want to allow access to everyone?': 'Êtes-vous sûr de vouloir autoriser l\'accès à tout le monde ?', 61 | 'Are you sure you want to stop all uploads?': 'Êtes-vous sûr de vouloir arrêter tous vos envois ?', 62 | 'Something went wrong': 'Quelque chose a mal tourné', 63 | 'Invalid directory': 'Dossier invalide', 64 | 'This field is required': 'Ce champ est obligatoire', 65 | 'Username already taken': 'Nom d\'utilisateur déjà utilisé', 66 | 'User not found': 'Utilisateur introuvable', 67 | 'Old password': 'Ancien mot de passe', 68 | 'New password': 'Nouveau mot de passe', 69 | 'Wrong password': 'Mot de passe incorrect', 70 | 'Updated': 'Mis à jour', 71 | 'Deleted': 'Supprimé', 72 | 'Your file is ready': 'Votre fichier est prêt', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Télécharger', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Afficher masqué', 78 | 'Large archive': 'Fichier compressé massif. Le fichier sera disponible bientôt. Veuillez rafraîchir le contenu de cette page dans quelques minutes...' 79 | } 80 | 81 | export default data 82 | 83 | -------------------------------------------------------------------------------- /frontend/translations/galician.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Seleccionados: {0} de {1}', 3 | 'Uploading files': 'Subindo arquivo {0}% de {1}', 4 | 'File size error': '{0} O arquivo é demasiado grande. Por favor, cargue arquivos de menos de {1}', 5 | 'Upload failed': '{0} Erro ao subir', 6 | 'Per page': '{0} Por páxina', 7 | 'Folder': 'Cartafol', 8 | 'Login failed, please try again': 'Houbo un erro no acceso, proba de novo.', 9 | 'Already logged in': 'Xa iniciaches sesión.', 10 | 'Please enter username and password': 'Por favor, insire usuario e contrasinal.', 11 | 'Not Found': 'Non se atopou', 12 | 'Not Allowed': 'Non permitido', 13 | 'Please log in': 'Por favor, inicie sesión', 14 | 'Unknown error': 'Erro descoñecido', 15 | 'Add files': 'Engadir Arquivos', 16 | 'New': 'Novo', 17 | 'New name': 'Novo nome', 18 | 'Username': 'Usuario', 19 | 'Password': 'Contrasinal', 20 | 'Login': 'Iniciar sesión', 21 | 'Logout': 'Saír', 22 | 'Profile': 'Perfil', 23 | 'No pagination': 'Sen paxinación', 24 | 'Time': 'Hora', 25 | 'Name': 'Nome', 26 | 'Size': 'Tamaño', 27 | 'Home': 'Inicio', 28 | 'Copy': 'Copiar', 29 | 'Move': 'Mover', 30 | 'Rename': 'Renomear', 31 | 'Required': 'Por favor, encha este campo', 32 | 'Zip': 'Arquivo comprimido', 33 | 'Batch Download': 'Descarga en lotes', 34 | 'Unzip': 'Descomprimir', 35 | 'Delete': 'Eliminar', 36 | 'Download': 'Baixar', 37 | 'Copy link': 'Copiar ligazón', 38 | 'Done': 'Feito', 39 | 'File': 'Arquivo', 40 | 'Drop files to upload': 'Arrastra e solta os arquivos para carregar', 41 | 'Close': 'Pechar', 42 | 'Select Folder': 'Escoller Cartafol', 43 | 'Users': 'Usuarios', 44 | 'Files': 'Arquivos', 45 | 'Role': 'Privilexio', 46 | 'Cancel': 'Cancelar', 47 | 'Paused': 'Pausado', 48 | 'Confirm': 'Confirmar', 49 | 'Create': 'Crear', 50 | 'User': 'Usuario', 51 | 'Admin': 'Administrador', 52 | 'Save': 'Gardar', 53 | 'Read': 'Ler', 54 | 'Write': 'Escribir', 55 | 'Upload': 'Carregar', 56 | 'Permissions': 'Permisos', 57 | 'Homedir': 'Cartafol de Inicio', 58 | 'Leave blank for no change': 'Deixa en branco para non facer cambios', 59 | 'Are you sure you want to do this?': 'Estás seguro de que queres facer isto?', 60 | 'Are you sure you want to allow access to everyone?': 'Estás seguro de que queres darlle acceso a calquera?', 61 | 'Are you sure you want to stop all uploads?': 'Estás seguro de que queres deter todas as cargas?', 62 | 'Something went wrong': 'Algo saíu mal', 63 | 'Invalid directory': 'Dirección non válida', 64 | 'This field is required': 'Este campo é obrigatorio', 65 | 'Username already taken': 'O usuario xa existe', 66 | 'User not found': 'Non se atopou o usuario', 67 | 'Old password': 'Contrasinal antiga', 68 | 'New password': 'Nova contrasinal', 69 | 'Wrong password': 'Contrasinal errada', 70 | 'Updated': 'Actualizado', 71 | 'Deleted': 'Eliminado', 72 | 'Your file is ready': 'O teu arquivo está listo', 73 | 'View': 'Ver', 74 | 'Show hidden': 'Amosar oculto', 75 | } 76 | 77 | export default data 78 | -------------------------------------------------------------------------------- /frontend/translations/german.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Ausgewählt: {0} von {1}', 3 | 'Uploading files': 'Hochladen: {0}% von {1}', 4 | 'File size error': '{0} ist zu groß, bitte nur Dateien hochladen, die kleiner als {1} sind.', 5 | 'Upload failed': '{0} wurde(n) nicht hochgeladen', 6 | 'Per page': '{0} pro Seite', 7 | 'Folder': 'Ordner', 8 | 'Login failed, please try again': 'Anmeldung fehlgeschlagen, bitte nochmal versuchen.', 9 | 'Already logged in': 'Bereits angemeldet', 10 | 'Please enter username and password': 'Bitte Benutzername und Passwort eingeben.', 11 | 'Not Found': 'Nicht gefunden', 12 | 'Not Allowed': 'Nicht erlaubt', 13 | 'Please log in': 'Bitte anmelden', 14 | 'Unknown error': 'Unbekannter Fehler', 15 | 'Add files': 'Dateien hinzufügen', 16 | 'New': 'Neu', 17 | 'New name': 'Neuer Name', 18 | 'Username': 'Benutzername', 19 | 'Password': 'Passwort', 20 | 'Login': 'Anmelden', 21 | 'Logout': 'Abmelden', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Kein Seitenumbruch', 24 | 'Time': 'Zeitpunkt', 25 | 'Name': 'Name', 26 | 'Size': 'Größe', 27 | 'Home': 'Home', 28 | 'Copy': 'Kopieren', 29 | 'Move': 'Verschieben', 30 | 'Rename': 'Umbenennen', 31 | 'Required': 'Bitte dieses Feld ausfüllen', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Batch Download', 34 | 'Unzip': 'Entpacken', 35 | 'Delete': 'Löschen', 36 | 'Download': 'Herunterladen', 37 | 'Copy link': 'Link kopieren', 38 | 'Done': 'Fertig', 39 | 'File': 'Datei', 40 | 'Drop files to upload': 'Dateien zum Hochladen hier ablegen', 41 | 'Close': 'Schließen', 42 | 'Select Folder': 'Ordner auswählen', 43 | 'Users': 'Benutzer', 44 | 'Files': 'Dateien', 45 | 'Role': 'Rolle', 46 | 'Cancel': 'Abbrechen', 47 | 'Paused': 'Pausiert', 48 | 'Confirm': 'Bestätigen', 49 | 'Create': 'Erstellen', 50 | 'User': 'Benutzer', 51 | 'Admin': 'Admin', 52 | 'Save': 'Speichern', 53 | 'Read': 'Lesen', 54 | 'Write': 'Schreiben', 55 | 'Upload': 'Hochladen', 56 | 'Permissions': 'Berechtigungen', 57 | 'Homedir': 'Home Ordner', 58 | 'Leave blank for no change': 'Leer lassen, um keine Änderung vorzunehmen', 59 | 'Are you sure you want to do this?': 'Sind Sie sicher, dass Sie das tun wollen?', 60 | 'Are you sure you want to allow access to everyone?': 'Sind Sie sicher, dass Sie jedem den Zugang ermöglichen wollen?', 61 | 'Are you sure you want to stop all uploads?': 'Sind Sie sicher, dass Sie alle Uploads stoppen wollen?', 62 | 'Something went wrong': 'Etwas ist schief gelaufen', 63 | 'Invalid directory': 'Ungültiges Verzeichnis', 64 | 'This field is required': 'Dieses Feld ist erforderlich', 65 | 'Username already taken': 'Benutzername bereits vergeben', 66 | 'User not found': 'Benutzer nicht gefunden', 67 | 'Old password': 'Altes Passwort', 68 | 'New password': 'Neues Passwort', 69 | 'Wrong password': 'Falsches Passwort', 70 | 'Updated': 'Aktualisiert', 71 | 'Deleted': 'Gelöscht', 72 | 'Your file is ready': 'Ihre Datei ist fertig', 73 | 'View': 'Ansicht', 74 | 'Search': 'Suche', 75 | 'Download permission': 'Herunterladen', 76 | 'Guest': 'Gast', 77 | 'Show hidden': 'Verborgenes zeigen', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/hungarian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Kijelölés: {0} Kijelölve {1}', 3 | 'Uploading files': 'Feltöltés {0}% Feltöltve {1}', 4 | 'File size error': '{0} Túl nagy fájl {1}', 5 | 'Upload failed': '{0} Sikertelen feltöltés', 6 | 'Per page': '{0} Oldalanként', 7 | 'Folder': 'Mappa', 8 | 'Login failed, please try again': 'Sikertelen belépés, próbálja újra', 9 | 'Already logged in': 'Bejelentkezve.', 10 | 'Please enter username and password': 'Kérjük, adja meg a felhasználónevét és jelszavát.', 11 | 'Not Found': 'Nem található', 12 | 'Not Allowed': 'Nem megengedett', 13 | 'Please log in': 'Kérjük jelentkezzen be', 14 | 'Unknown error': 'Ismeretlen hiba', 15 | 'Add files': 'Fájl hozzáadása', 16 | 'New': 'Új', 17 | 'New name': 'Új felhasználó', 18 | 'Username': 'Felhasználónév', 19 | 'Password': 'Jelszó', 20 | 'Login': 'Belépés', 21 | 'Logout': 'Kilépés', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Nincs lap', 24 | 'Time': 'Idő', 25 | 'Name': 'Név', 26 | 'Size': 'Méret', 27 | 'Home': 'Főkönyvtár', 28 | 'Copy': 'Másol', 29 | 'Move': 'Áthelyez', 30 | 'Rename': 'Átnevez', 31 | 'Required': 'Kérem töltse ki ezt a mezőt', 32 | 'Zip': 'Becsomagol', 33 | 'Batch Download': 'Kötegelt letöltés', 34 | 'Unzip': 'Kicsomagolás', 35 | 'Delete': 'Törlés', 36 | 'Download': 'Letöltés', 37 | 'Copy link': 'Link másolása', 38 | 'Done': 'Kész', 39 | 'File': 'Fájl', 40 | 'Drop files to upload': 'Dobja el a feltöltendő fájlokat', 41 | 'Close': 'Bezár', 42 | 'Select Folder': 'Mappa kijelölése', 43 | 'Users': 'Felhasználók', 44 | 'Files': 'Fájlok', 45 | 'Role': 'Szerep', 46 | 'Cancel': 'Mégse', 47 | 'Paused': 'Szünetel', 48 | 'Confirm': 'Megerősít', 49 | 'Create': 'Létrehoz', 50 | 'User': 'Felhasználó', 51 | 'Admin': 'Adminisztrátor', 52 | 'Save': 'Mentés', 53 | 'Read': 'Olvasás', 54 | 'Write': 'Írás', 55 | 'Upload': 'Feltöltés', 56 | 'Permissions': 'Engedélyek', 57 | 'Homedir': 'Fő mappa', 58 | 'Leave blank for no change': 'Hagyja üresen változtatás nélkül', 59 | 'Are you sure you want to do this?': 'Biztosan meg akarja változtatni?', 60 | 'Are you sure you want to allow access to everyone?': 'Biztos, hogy mindenkinek engedélyezi a hozzáférést?', 61 | 'Are you sure you want to stop all uploads?': 'Biztosan leállítja az összes feltöltést?', 62 | 'Something went wrong': 'Valami elromlott', 63 | 'Invalid directory': 'Érvénytelen mappa', 64 | 'This field is required': 'Mező kitöltése kötelező', 65 | 'Username already taken': 'A felhasználónév már foglalt', 66 | 'User not found': 'Felhasználó nem található', 67 | 'Old password': 'Régi jelszó', 68 | 'New password': 'Új jelszó', 69 | 'Wrong password': 'Rossz jelszó', 70 | 'Updated': 'Feltöltés', 71 | 'Deleted': 'Törlés', 72 | 'Your file is ready': 'Your file is ready', 73 | 'View': 'Nézet', 74 | 'Search': 'Keresés', 75 | 'Download permission': 'Letöltés engedélyezés', 76 | 'Guest': 'Vendég', 77 | 'Show hidden': 'Rejtett megjelenítése', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/indonesian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Terpilih: {0} of {1}', 3 | 'Uploading files': 'Mengunggah {0}% of {1}', 4 | 'File size error': '{0} terlalu besar, harap unggah file lebih kecil dari {1}', 5 | 'Upload failed': '{0} gagal diunggah', 6 | 'Per page': '{0} Per Halaman', 7 | 'Folder': 'Berkas', 8 | 'Login failed, please try again': 'Gagal masuk, silakan coba lagi', 9 | 'Already logged in': 'Telah masuk.', 10 | 'Please enter username and password': 'Silahkan masukan nama pengguna dan kata sandi.', 11 | 'Not Found': 'Tidak ditemukan', 12 | 'Not Allowed': 'Tidak dibolehkan', 13 | 'Please log in': 'Silahkan masuk', 14 | 'Unknown error': 'Kesalahan tidak dikenal', 15 | 'Add files': 'Tambahkan berkas', 16 | 'New': 'Baru', 17 | 'New name': 'Nama baru', 18 | 'Username': 'Nama pengguna', 19 | 'Password': 'Kata sandi', 20 | 'Login': 'Masuk', 21 | 'Logout': 'Keluar', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Tidak ada halaman', 24 | 'Time': 'Waktu', 25 | 'Name': 'Nama', 26 | 'Size': 'Ukuran', 27 | 'Home': 'Rumah', 28 | 'Copy': 'Salin', 29 | 'Move': 'Pindah', 30 | 'Rename': 'Ubah nama', 31 | 'Required': 'Silakan isi bidang ini', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Unduh Batch', 34 | 'Unzip': 'Unzip', 35 | 'Delete': 'Hapus', 36 | 'Download': 'Unduh', 37 | 'Copy link': 'Salin tautan', 38 | 'Done': 'Selesai', 39 | 'File': 'File', 40 | 'Drop files to upload': 'Letakkan file untuk diunggah', 41 | 'Close': 'Tutup', 42 | 'Select Folder': 'Pilih Berkas', 43 | 'Users': 'Pengguna', 44 | 'Files': 'Arsip', 45 | 'Role': 'Peran', 46 | 'Cancel': 'Batal', 47 | 'Paused': 'Dijeda', 48 | 'Confirm': 'Konfirmasi', 49 | 'Create': 'Buat', 50 | 'User': 'Pengguna', 51 | 'Admin': 'Admin', 52 | 'Save': 'Simpan', 53 | 'Read': 'Baca', 54 | 'Write': 'Tulis', 55 | 'Upload': 'Unggah', 56 | 'Permissions': 'Izin', 57 | 'Homedir': 'Direktori Rumah', 58 | 'Leave blank for no change': 'Biarkan kosong tanpa perubahan', 59 | 'Are you sure you want to do this?': 'Anda yakin ingin melakukan ini?', 60 | 'Are you sure you want to allow access to everyone?': 'Apakah anda yakin ingin mengizinkan akses ke semua orang?', 61 | 'Are you sure you want to stop all uploads?': 'Apakah anda yakin ingin menghentikan semua unggahan?', 62 | 'Something went wrong': 'Ada yang salah', 63 | 'Invalid directory': 'Direktori salah', 64 | 'This field is required': 'Bagian ini diperlukan', 65 | 'Username already taken': 'Nama pengguna sudah digunakan', 66 | 'User not found': 'Pengguna tidak ditemukan', 67 | 'Old password': 'Kata sandi lama', 68 | 'New password': 'Kata sandi baru', 69 | 'Wrong password': 'Kata sandi salah', 70 | 'Updated': 'Diperbarui', 71 | 'Deleted': 'Dihapus', 72 | 'Your file is ready': 'File Anda sudah siap', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Unduh', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Tunjukkan tersembunyi', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/italian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Selezionati: {0} di {1}', 3 | 'Uploading files': 'Caricamento {0}% di {1}', 4 | 'File size error': '{0} File troppo grande. Dimensione massima consentita {1}', 5 | 'Upload failed': '{0} Caricamento fallito', 6 | 'Per page': '{0} per pagina', 7 | 'Folder': 'Cartella', 8 | 'Login failed, please try again': 'Username o password non corretti', 9 | 'Already logged in': 'Sei già connesso', 10 | 'Please enter username and password': 'Inserisci username e password', 11 | 'Not Found': 'Nessun risultato', 12 | 'Not Allowed': 'Non consentito', 13 | 'Please log in': 'Per cortesia autenticati', 14 | 'Unknown error': 'Errore sconosciuto', 15 | 'Add files': 'Aggiungi files', 16 | 'New': 'Nuovo', 17 | 'New name': 'Nuovo nome', 18 | 'Username': 'Username', 19 | 'Password': 'Password', 20 | 'Login': 'Entra', 21 | 'Logout': 'Esci', 22 | 'Profile': 'Cambia password', 23 | 'No pagination': 'Uno per pagina', 24 | 'Time': 'Data', 25 | 'Name': 'Nome', 26 | 'Size': 'Dimensione', 27 | 'Home': 'Cartella principale', 28 | 'Copy': 'Copia', 29 | 'Move': 'Sposta', 30 | 'Rename': 'Rinomina', 31 | 'Required': 'Campo obbligatorio', 32 | 'Zip': 'Comprimi', 33 | 'Batch Download': 'Scarica batch', 34 | 'Unzip': 'Estrai', 35 | 'Delete': 'Elimina', 36 | 'Download': 'Scarica', 37 | 'Copy link': 'Copia collegamento', 38 | 'Done': 'Completato', 39 | 'File': 'File', 40 | 'Drop files to upload': 'Trascina i files che vuoi caricare', 41 | 'Close': 'Chiudi', 42 | 'Select Folder': 'Seleziona cartella', 43 | 'Users': 'Utenti', 44 | 'Files': 'Files', 45 | 'Role': 'Ruolo', 46 | 'Cancel': 'Annulla', 47 | 'Paused': 'Sospeso', 48 | 'Confirm': 'Conferma', 49 | 'Create': 'Crea', 50 | 'User': 'Utente', 51 | 'Admin': 'Amministratore', 52 | 'Save': 'Salva', 53 | 'Read': 'Lettura', 54 | 'Write': 'Scrittura', 55 | 'Upload': 'Caricamento', 56 | 'Permissions': 'Permessi', 57 | 'Homedir': 'Cartella principale', 58 | 'Leave blank for no change': 'Lascia in bianco per non effettuare modifiche', 59 | 'Are you sure you want to do this?': 'Sei sicuro di voler eliminare gli elementi selezionati?', 60 | 'Are you sure you want to allow access to everyone?': 'Sei sicuro di voler consentire libero accesso a tutti?', 61 | 'Are you sure you want to stop all uploads?': 'Vuoi sospendere tutti i caricamenti?', 62 | 'Something went wrong': 'Qualcosa é andato storto', 63 | 'Invalid directory': 'Cartella non corretta', 64 | 'This field is required': 'Questo campo é obbligatorio', 65 | 'Username already taken': 'Username giá esistente', 66 | 'User not found': 'Utente non trovato', 67 | 'Old password': 'Vecchia password', 68 | 'New password': 'Nuova password', 69 | 'Wrong password': 'Password errata', 70 | 'Updated': 'Aggiornato', 71 | 'Deleted': 'Eliminato', 72 | 'Your file is ready': 'Il tuo file è disponibile', 73 | 'View': 'Leggi', 74 | 'Search': 'Cerca', 75 | 'Download permission': 'Scarica', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Mostra nascosto', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/japanese.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': '{0}個中{1}個を選択中', 3 | 'Uploading files': '{1}中{0}%をアップロードしています…', 4 | 'File size error': '{0}が大きすぎます。{1}未満のファイルのみアップロードできます。', 5 | 'Upload failed': '{0}のアップロードに失敗しました。', 6 | 'Per page': '{0}個表示', 7 | 'Folder': 'フォルダ', 8 | 'Login failed, please try again': 'ログインに失敗しました。もう1度お試しください。', 9 | 'Already logged in': '既にログインしています。', 10 | 'Please enter username and password': 'ユーザー名とパスワードを入力してください。', 11 | 'Not Found': '見つかりません。', 12 | 'Not Allowed': '許可されていません。', 13 | 'Please log in': 'ログインしてください', 14 | 'Unknown error': '不明なエラー', 15 | 'Add files': 'アップロード', 16 | 'New': '新規', 17 | 'New name': '新しい名前', 18 | 'Username': 'ユーザー名', 19 | 'Password': 'パスワード', 20 | 'Login': 'ログイン', 21 | 'Logout': 'ログアウト', 22 | 'Profile': 'プロフィール', 23 | 'No pagination': 'ページネーションなし', 24 | 'Time': '更新日', 25 | 'Name': '名前', 26 | 'Size': 'サイズ', 27 | 'Home': 'ホーム', 28 | 'Copy': 'コピー', 29 | 'Move': '移動', 30 | 'Rename': '名前の変更', 31 | 'Required': 'このフィールドを記入してください。', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'バッチダウンロード', 34 | 'Unzip': 'Zipを解凍', 35 | 'Delete': '削除', 36 | 'Download': 'ダウンロード', 37 | 'Copy link': 'リンクをコピー', 38 | 'Done': '完了', 39 | 'File': 'ファイル', 40 | 'Drop files to upload': 'アップロードするファイルをドロップしてください。', 41 | 'Close': '閉じる', 42 | 'Select Folder': 'フォルダを選択', 43 | 'Users': 'ユーザー', 44 | 'Files': 'ファイル', 45 | 'Role': 'ロール', 46 | 'Cancel': 'キャンセル', 47 | 'Paused': '一時停止', 48 | 'Confirm': '確認', 49 | 'Create': '作成', 50 | 'User': 'ユーザー', 51 | 'Admin': '管理者', 52 | 'Save': '保存', 53 | 'Read': '読み込み', 54 | 'Write': '書き込み', 55 | 'Upload': 'アップロード', 56 | 'Permissions': '権限', 57 | 'Homedir': 'ホームフォルダ', 58 | 'Leave blank for no change': '変更しない場合は空白のままにしてください', 59 | 'Are you sure you want to do this?': '実行してもよろしいですか?', 60 | 'Are you sure you want to allow access to everyone?': '全員にアクセスを許可してよろしいですか?', 61 | 'Are you sure you want to stop all uploads?': '全てのアップロードを中止してよろしいですか?', 62 | 'Something went wrong': '問題が発生したようです。', 63 | 'Invalid directory': '無効なフォルダ', 64 | 'This field is required': 'この項目は必須です。', 65 | 'Username already taken': 'ユーザー名が既に使用されています。', 66 | 'User not found': 'ユーザーが見つかりません。', 67 | 'Old password': '以前のパスワード', 68 | 'New password': '新しいパスワード', 69 | 'Wrong password': 'パスワードが間違っています。', 70 | 'Updated': '更新しました。', 71 | 'Deleted': '削除しました。', 72 | 'Your file is ready': 'ファイルの準備ができました。', 73 | 'View': '表示', 74 | } 75 | 76 | export default data 77 | -------------------------------------------------------------------------------- /frontend/translations/korean.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': '선택된 항목: {0}/{1}', 3 | 'Uploading files': '{1} 중 {0}% 업로드 진행', 4 | 'File size error': '{1} 이하의 파일만 업로드가 가능합니다.', 5 | 'Upload failed': '{0} 업로드 실패', 6 | 'Per page': '{0}개씩 보기', 7 | 'Folder': '폴더', 8 | 'Login failed, please try again': '로그인 실패, 다시 시도하십시오.', 9 | 'Already logged in': '이미 로그인되었습니다.', 10 | 'Please enter username and password': '사용자 이름과 비밀번호를 입력하십시오.', 11 | 'Not Found': '찾을 수 없음', 12 | 'Not Allowed': '허용되지 않음', 13 | 'Please log in': '로그인하십시오.', 14 | 'Unknown error': '알 수 없는 오류', 15 | 'Add files': '업로드', 16 | 'New': '생성', 17 | 'New name': '변경할 이름', 18 | 'Username': '사용자 이름', 19 | 'Password': '비밀번호', 20 | 'Login': '로그인', 21 | 'Logout': '로그아웃', 22 | 'Profile': '프로필', 23 | 'No pagination': '전체 보기', 24 | 'Time': '수정한 날짜', 25 | 'Name': '이름', 26 | 'Size': '크기', 27 | 'Home': '홈', 28 | 'Copy': '복사', 29 | 'Move': '이동', 30 | 'Rename': '이름 변경', 31 | 'Required': '이 필드를 작성하십시오.', 32 | 'Zip': '압축', 33 | 'Batch Download': '일괄 다운로드', 34 | 'Unzip': '압축 해제', 35 | 'Delete': '삭제', 36 | 'Download': '다운로드', 37 | 'Copy link': '링크 복사', 38 | 'Done': '완료', 39 | 'File': '파일', 40 | 'Drop files to upload': '업로드할 파일을 끌어서 놓으십시오.', 41 | 'Close': '닫기', 42 | 'Select Folder': '폴더 선택', 43 | 'Users': '사용자', 44 | 'Files': '파일', 45 | 'Role': '역할', 46 | 'Cancel': '취소', 47 | 'Paused': '일시중지됨', 48 | 'Confirm': '확인', 49 | 'Create': '생성', 50 | 'User': '사용자', 51 | 'Admin': '관리자', 52 | 'Save': '저장', 53 | 'Read': '읽기', 54 | 'Write': '쓰기', 55 | 'Upload': '업로드', 56 | 'Permissions': '권한', 57 | 'Homedir': '홈 폴더', 58 | 'Leave blank for no change': '변경하지 않으려면 비워 두십시오.', 59 | 'Are you sure you want to do this?': '이 작업을 수행하시겠습니까?', 60 | 'Are you sure you want to allow access to everyone?': '방문자에게 접근을 허용하시겠습니까?', 61 | 'Are you sure you want to stop all uploads?': '모든 업로드를 중지하시겠습니까?', 62 | 'Something went wrong': '오류가 발생했습니다.', 63 | 'Invalid directory': '잘못된 폴더', 64 | 'This field is required': '이 필드는 필수입니다.', 65 | 'Username already taken': '이미 사용 중인 사용자 이름입니다.', 66 | 'User not found': '사용자를 찾을 수 없습니다.', 67 | 'Old password': '현재 비밀번호', 68 | 'New password': '새 비밀번호', 69 | 'Wrong password': '잘못된 비밀번호', 70 | 'Updated': '업데이트됨', 71 | 'Deleted': '삭제됨', 72 | 'Your file is ready': '파일이 준비되었습니다.', 73 | 'View': '보기', 74 | 'Search': '검색', 75 | 'Download permission': '다운로드', 76 | 'Guest': '방문자', 77 | 'Show hidden': '숨김 표시', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/lithuanian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Pasirinkta: {0} iš {1}', 3 | 'Uploading files': 'Įkeliama {0}% iš {1}', 4 | 'File size error': '{0} yra per didelis, prašome įkelti mažesnius failus nei {1}', 5 | 'Upload failed': '{0} nepavyko įkelti', 6 | 'Per page': '{0} puslapyje', 7 | 'Folder': 'Aplankas', 8 | 'Login failed, please try again': 'Nepavyko prisijungti, bandykite dar kartą', 9 | 'Already logged in': 'Jau esate prisijungęs.', 10 | 'Please enter username and password': 'Prašome įvesti prisijungimo vardą ir slaptažodį.', 11 | 'Not Found': 'Nerasta', 12 | 'Not Allowed': 'Neleidžiama', 13 | 'Please log in': 'Prašome prisijungti', 14 | 'Unknown error': 'Nežinoma klaida', 15 | 'Add files': 'Įkelti failus', 16 | 'New': 'Naujas', 17 | 'New name': 'Naujas pavadinimas', 18 | 'Username': 'Prisijungimo vardas', 19 | 'Password': 'Slaptažodis', 20 | 'Login': 'Prisijungti', 21 | 'Logout': 'Atsijungti', 22 | 'Profile': 'Profilis', 23 | 'No pagination': 'Nepuslapiuoti', 24 | 'Time': 'Laikas', 25 | 'Name': 'Pavadinimas', 26 | 'Size': 'Dydis', 27 | 'Home': 'Pradžia', 28 | 'Copy': 'Kopijuoti', 29 | 'Move': 'Perkelti', 30 | 'Rename': 'Pervadinti', 31 | 'Required': 'Prašome užpildyti šį lauką', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Atsiųsti paketą', 34 | 'Unzip': 'Išpakuoti', 35 | 'Delete': 'Pašalinti', 36 | 'Download': 'Atsiųsti', 37 | 'Copy link': 'Kopijuoti nuorodą', 38 | 'Done': 'Atlikta', 39 | 'File': 'Failas', 40 | 'Drop files to upload': 'Nutempti failus įkėlimui', 41 | 'Close': 'Užverti', 42 | 'Select Folder': 'Pasirinkite aplanką', 43 | 'Users': 'Vartotojai', 44 | 'Files': 'Failai', 45 | 'Role': 'Vaidmuo', 46 | 'Cancel': 'Atšaukti', 47 | 'Paused': 'Pristabdytas', 48 | 'Confirm': 'Patvirtinti', 49 | 'Create': 'Sukurti', 50 | 'User': 'Vartotojas', 51 | 'Admin': 'Admin', 52 | 'Save': 'Išsaugoti', 53 | 'Read': 'Nuskaityti', 54 | 'Write': 'Įrašyti', 55 | 'Upload': 'Įkelti', 56 | 'Permissions': 'Leidimai', 57 | 'Homedir': 'Pradžios aplankas', 58 | 'Leave blank for no change': 'Palikite tuščią, jei nenorite nieko keisti', 59 | 'Are you sure you want to do this?': 'Ar Jūs įsitikinęs, kad norite tai atlikti?', 60 | 'Are you sure you want to allow access to everyone?': 'Ar Jūs įsitikinęs, kad norite atverti prieigą prie failų bet kam?', 61 | 'Are you sure you want to stop all uploads?': 'Ar Jūs įsitikinęs, kad norite sustabdyti visus įkėlimus?', 62 | 'Something went wrong': 'Kažkas negerai', 63 | 'Invalid directory': 'Neteisingas aplankas', 64 | 'This field is required': 'Šį lauką privalote užpildyti', 65 | 'Username already taken': 'Toks prisijungimo vardas jau egzistuoja', 66 | 'User not found': 'Vartotojas nerastas', 67 | 'Old password': 'Senas slaptažodis', 68 | 'New password': 'Naujas slaptažodis', 69 | 'Wrong password': 'Klaidingas slaptažodis', 70 | 'Updated': 'Atnaujintas', 71 | 'Deleted': 'Ištrintas', 72 | 'Your file is ready': 'Jūsų failas paruoštas', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Atsiųsti', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Rodyti paslėptą', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/polish.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Wybrano: {0} z {1}', 3 | 'Uploading files': 'Przesyłanie {0}% z {1}', 4 | 'Błąd rozmiaru pliku': '{0} jest za duży, prześlij mniejszy plik {1}', 5 | 'Upload failed': '{0} plików nie udało się przesłać', 6 | 'Per page': '{0} Na stronę', 7 | 'Folder': 'Folder', 8 | 'Login failed, please try again': 'Zły login lub hasło.', 9 | 'Already logged in': 'Already logged in.', 10 | 'Please enter username and password': 'Wpisz login i hasło.', 11 | 'Not Found': 'Nie znaleziono', 12 | 'Not Allowed': 'Nie dozwolony', 13 | 'Please log in': 'Proszę się zalogować', 14 | 'Unknown error': 'Nieznany błąd', 15 | 'Add files': 'Dodaj plik', 16 | 'New': 'Nowy', 17 | 'New name': 'Nowa nazwa', 18 | 'Username': 'Login', 19 | 'Password': 'Hasło', 20 | 'Login': 'Zaloguj', 21 | 'Logout': 'Wyloguj', 22 | 'Profile': 'Profile', 23 | 'No pagination': 'Brak podziału na strony', 24 | 'Time': 'Czas', 25 | 'Name': 'Nazwa', 26 | 'Size': 'Rozmiar', 27 | 'Home': 'Folder główny', 28 | 'Copy': 'Kopiuj', 29 | 'Move': 'Przenieś', 30 | 'Rename': 'Zmień nazwę', 31 | 'Required': 'Proszę wypełnić to pole', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Pobieranie zbiorcze', 34 | 'Unzip': 'Rozpakuj', 35 | 'Delete': 'Usuń', 36 | 'Download': 'Download', 37 | 'Copy link': 'Kopiuj link', 38 | 'Done': 'Done', 39 | 'File': 'Plik', 40 | 'Drop files to upload': 'Upuść pliki do przesłania', 41 | 'Close': 'Zamknij', 42 | 'Select Folder': 'Wybierz katalog', 43 | 'Users': 'Użytkownik', 44 | 'Files': 'Pliki', 45 | 'Role': 'Role', 46 | 'Cancel': 'Anuluj', 47 | 'Paused': 'Pauza', 48 | 'Confirm': 'Potwierdź', 49 | 'Create': 'Stwórz', 50 | 'User': 'Użytkownik', 51 | 'Admin': 'Admin', 52 | 'Save': 'Zapisz', 53 | 'Read': 'Podgląd', 54 | 'Write': 'Zapisz', 55 | 'Upload': 'Upload', 56 | 'Permissions': 'Uprawnienia', 57 | 'Homedir': 'Folder Główny', 58 | 'Leave blank for no change': 'Pozostaw puste, bez zmian', 59 | 'Are you sure you want to do this?': 'Jesteś pewny że chcesz to zrobić?', 60 | 'Are you sure you want to allow access to everyone?': 'Czy na pewno chcesz zezwolić na dostęp wszystkim?', 61 | 'Are you sure you want to stop all uploads?': 'Czy na pewno chcesz zatrzymać wszystkie przesyłane pliki?', 62 | 'Something went wrong': 'Coś poszło nie tak', 63 | 'Invalid directory': 'Nieprawidłowy katalog', 64 | 'This field is required': 'To pole jest wymagane', 65 | 'Username already taken': 'Nazwa użytkownika zajęta', 66 | 'User not found': 'Użytkownik nie znaleziony', 67 | 'Old password': 'Stare hasło', 68 | 'New password': 'Nowe hasło', 69 | 'Wrong password': 'Nieprawidłowe hasło', 70 | 'Updated': 'Zaktualizowano', 71 | 'Deleted': 'Usunięte', 72 | 'Your file is ready': 'Twój plik jest gotowy', 73 | 'View': 'Podgląd', 74 | 'Search': 'Szukaj', 75 | 'Download permission': 'Download', 76 | 'Guest': 'Gość', 77 | 'Show hidden': 'Pokaż ukryte', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/portuguese.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Selecionado: {0} de {1}', 3 | 'Uploading files': 'Fazendo o upload {0}% de {1}', 4 | 'File size error': '{0} é muito grande, por favor faça upload de arquivos menores que {1}', 5 | 'Upload failed': '{0} falhou ao fazer o upload', 6 | 'Per page': '{0} Por página', 7 | 'Folder': 'Diretório', 8 | 'Login failed, please try again': 'Login falhou, por favor tente novamente', 9 | 'Already logged in': 'Já está logado', 10 | 'Please enter username and password': 'Por favor entre com o nome de usuário e a senha', 11 | 'Not Found': 'Não encontrado', 12 | 'Not Allowed': 'Não autorizado', 13 | 'Please log in': 'Por favor faça o login', 14 | 'Unknown error': 'Erro desconhecido', 15 | 'Add files': 'Adicionar arquivos', 16 | 'New': 'Novo', 17 | 'New name': 'Novo nome', 18 | 'Username': 'Nome de usuário', 19 | 'Password': 'Senha', 20 | 'Login': 'Entrar', 21 | 'Logout': 'Sair', 22 | 'Profile': 'Perfil', 23 | 'No pagination': 'Sem paginação', 24 | 'Time': 'Data', 25 | 'Name': 'Nome', 26 | 'Size': 'Tamanho', 27 | 'Home': 'Página inicial', 28 | 'Copy': 'Copiar', 29 | 'Move': 'Mover', 30 | 'Rename': 'Renomear', 31 | 'Required': 'Por favor preencha este campo', 32 | 'Zip': 'Comprimir', 33 | 'Batch Download': 'Download em lote', 34 | 'Unzip': 'Descomprimir', 35 | 'Delete': 'Deletar', 36 | 'Download': 'Download', 37 | 'Copy link': 'Copiar link', 38 | 'Done': 'Finalizado', 39 | 'File': 'Arquivo', 40 | 'Drop files to upload': 'Arraste arquivos para fazer o upload', 41 | 'Close': 'Fechar', 42 | 'Select Folder': 'Selecionar diretório', 43 | 'Users': 'Usuários', 44 | 'Files': 'Arquivos', 45 | 'Role': 'Perfil', 46 | 'Cancel': 'Cancelar', 47 | 'Paused': 'Pausado', 48 | 'Confirm': 'Confirmar', 49 | 'Create': 'Criar', 50 | 'User': 'Usuário', 51 | 'Admin': 'Administrador', 52 | 'Save': 'Salvar', 53 | 'Read': 'Ler', 54 | 'Write': 'Escrever', 55 | 'Upload': 'Upload', 56 | 'Permissions': 'Permissões', 57 | 'Homedir': 'Página inicial', 58 | 'Leave blank for no change': 'Deixe em branco para não fazer nenhuma alteração', 59 | 'Are you sure you want to do this?': 'Tem certeza que deseja fazer isto?', 60 | 'Are you sure you want to allow access to everyone?': 'Tem certeza que deseja permitir o acesso a todos?', 61 | 'Are you sure you want to stop all uploads?': 'Tem certeza que deseja parar todos os uploads?', 62 | 'Something went wrong': 'Algo deu errado', 63 | 'Invalid directory': 'Diretório inválido', 64 | 'This field is required': 'Este campo é obrigatório', 65 | 'Username already taken': 'O nome de usuário já existe', 66 | 'User not found': 'Usuário não encontrado', 67 | 'Old password': 'Senha atual', 68 | 'New password': 'Nova senha', 69 | 'Wrong password': 'Senha inválida', 70 | 'Updated': 'Atualizado', 71 | 'Deleted': 'Excluído', 72 | 'Your file is ready': 'Seu arquivo está pronto', 73 | 'View': 'Visualizar', 74 | 'Search': 'Procurar', 75 | 'Download permission': 'Download', 76 | 'Guest': 'Convidado', 77 | 'Show hidden': 'Mostrar ocultos', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/russian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Выбрано: {0} из {1}', 3 | 'Uploading files': 'Загрузка {0}% of {1}', 4 | 'File size error': '{0} слишком большой, пожалуйста, загрузите файл меньше {1}', 5 | 'Upload failed': '{0} не удалось загрузить', 6 | 'Per page': '{0} На страницу', 7 | 'Folder': 'Папка', 8 | 'Login failed, please try again': 'Вход не выполнен. Пожалуйста попробуйте еще раз', 9 | 'Already logged in': 'Уже авторизован.', 10 | 'Please enter username and password': 'Пожалуйста, введите имя пользователя и пароль.', 11 | 'Not Found': 'Не найдено', 12 | 'Not Allowed': 'Не разрешено', 13 | 'Please log in': 'Пожалуйста, войдите', 14 | 'Unknown error': 'Неизвестная ошибка', 15 | 'Add files': 'Добавить файлы', 16 | 'New': 'Создать', 17 | 'New name': 'Новое имя', 18 | 'Username': 'Имя пользователя', 19 | 'Password': 'Пароль', 20 | 'Login': 'Вход', 21 | 'Logout': 'Выход', 22 | 'Profile': 'Профиль', 23 | 'No pagination': 'Без разбивки на страницы', 24 | 'Time': 'Время', 25 | 'Name': 'Имя', 26 | 'Size': 'Размер', 27 | 'Home': 'Главная', 28 | 'Copy': 'Копировать', 29 | 'Move': 'Переместить', 30 | 'Rename': 'Переименовать', 31 | 'Required': 'Пожалуйста, заполните это поле', 32 | 'Zip': 'Архивировать zip', 33 | 'Batch Download': 'Пакетная загрузка', 34 | 'Unzip': 'Разархивировать zip архив', 35 | 'Delete': 'Удалить', 36 | 'Download': 'Скачать', 37 | 'Copy link': 'Скопировать ссылку', 38 | 'Done': 'Готово', 39 | 'File': 'Файл', 40 | 'Drop files to upload': 'Перетащите файлы для загрузки', 41 | 'Close': 'Закрыть', 42 | 'Select Folder': 'Выберите папку', 43 | 'Users': 'Пользователи', 44 | 'Files': 'Файлы', 45 | 'Role': 'Роли', 46 | 'Cancel': 'Отмена', 47 | 'Paused': 'Приостановлено', 48 | 'Confirm': 'Подтвердить', 49 | 'Create': 'Создать', 50 | 'User': 'Пользователь', 51 | 'Admin': 'Админ', 52 | 'Save': 'Сохранить', 53 | 'Read': 'Чтение', 54 | 'Write': 'Запись', 55 | 'Upload': 'Загрузка', 56 | 'Permissions': 'Разрешения', 57 | 'Homedir': 'Домашняя папка', 58 | 'Leave blank for no change': 'Оставьте поле пустым, чтобы оставить без изменений', 59 | 'Are you sure you want to do this?': 'Вы уверены, что хотите выполнить это действие?', 60 | 'Are you sure you want to allow access to everyone?': 'Вы уверены, что хотите предоставить доступ всем?', 61 | 'Are you sure you want to stop all uploads?': 'Вы уверены, что хотите остановить все загрузки?', 62 | 'Something went wrong': 'Что-то пошло не так', 63 | 'Invalid directory': 'Недействительная папка', 64 | 'This field is required': 'Это поле обязательное', 65 | 'Username already taken': 'Имя пользователя уже занято', 66 | 'User not found': 'Пользователь не найден', 67 | 'Old password': 'Старый пароль', 68 | 'New password': 'Новый пароль', 69 | 'Wrong password': 'Неверный пароль', 70 | 'Updated': 'Обновлено', 71 | 'Deleted': 'Удалено', 72 | 'Your file is ready': 'Ваш файл готов', 73 | 'View': 'Просмотр', 74 | 'Search': 'Поиск', 75 | 'Download permission': 'Скачивание', 76 | 'Guest': 'Гость', 77 | 'Show hidden': 'Показать скрытое', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/serbian.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Izabrano: {0} od {1}', 3 | 'Uploading files': 'Slanje {0}% od {1}', 4 | 'File size error': '{0} fajl je preveliki, molim pošaljite fajl manji od {1}', 5 | 'Upload failed': '{0} greška kod slanja', 6 | 'Per page': '{0} Po strani', 7 | 'Folder': 'Folder', 8 | 'Login failed, please try again': 'Neuspešna prijava, probajte ponovo', 9 | 'Already logged in': 'Već prijavljen.', 10 | 'Please enter username and password': 'Unesite korisničko ime i lozinku.', 11 | 'Not Found': 'Nije pronađen', 12 | 'Not Allowed': 'Nije dozvoljeno', 13 | 'Please log in': 'Molim prijavite se', 14 | 'Unknown error': 'Nepoznata greška', 15 | 'Add files': 'Dodaj fajlove', 16 | 'New': 'Novi', 17 | 'New name': 'Novo ime', 18 | 'Username': 'Korisničko ime', 19 | 'Password': 'Lozinka', 20 | 'Login': 'Prijavi se', 21 | 'Logout': 'Odjavi se', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Bez listanja po strani', 24 | 'Time': 'Vreme', 25 | 'Name': 'Ime', 26 | 'Size': 'Veličina', 27 | 'Home': 'Početna', 28 | 'Copy': 'Kopiraj', 29 | 'Move': 'Premesti', 30 | 'Rename': 'Promeni ime', 31 | 'Required': 'Ovo polje je obavezno', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Grupno preuzimanje', 34 | 'Unzip': 'Unzip', 35 | 'Delete': 'Obriši', 36 | 'Download': 'Preuzmi', 37 | 'Copy link': 'Kopiraj link', 38 | 'Done': 'Gotovo', 39 | 'File': 'Fajl', 40 | 'Drop files to upload': 'Spusti fajlove za slanje', 41 | 'Close': 'Zatvori', 42 | 'Select Folder': 'Izaberi folder', 43 | 'Users': 'Korisnici', 44 | 'Files': 'Fajlovi', 45 | 'Role': 'Prava', 46 | 'Cancel': 'Otkaži', 47 | 'Paused': 'Pauzirano', 48 | 'Confirm': 'Potvrdi', 49 | 'Create': 'Kreiraj', 50 | 'User': 'Korisnik', 51 | 'Admin': 'Administrator', 52 | 'Save': 'Sačuvaj', 53 | 'Read': 'Čitanje', 54 | 'Write': 'Upis', 55 | 'Upload': 'Slanje', 56 | 'Permissions': 'Prava pristupa', 57 | 'Homedir': 'Početni folder', 58 | 'Leave blank for no change': 'Ostavi prazno da ne promeniš', 59 | 'Are you sure you want to do this?': 'Da li ste sigurni?', 60 | 'Are you sure you want to allow access to everyone?': 'Da li ste sigurni da želite da dozvolite pristup svima?', 61 | 'Are you sure you want to stop all uploads?': 'Da li ste sigurni da želite da prekinete sva slanja?', 62 | 'Something went wrong': 'Dogodila se nepoznata greška', 63 | 'Invalid directory': 'Pogrešan folder', 64 | 'This field is required': 'Ovo polje je obavezno', 65 | 'Username already taken': 'Korisničko ime već postoji', 66 | 'User not found': 'Korisnik nije pronađen', 67 | 'Old password': 'Stara lozinka', 68 | 'New password': 'Nova lozinka', 69 | 'Wrong password': 'Pogrešna lozinka', 70 | 'Updated': 'Izmenjeno', 71 | 'Deleted': 'Obrisano', 72 | 'Your file is ready': 'Vaš fajl je spreman', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Preuzimanje', 76 | 'Guest': 'Gost', 77 | 'Show hidden': 'Prikaži skriveno', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/slovak.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Vybrané: {0} z {1}', 3 | 'Uploading files': 'Nahrávam {0}% z {1}', 4 | 'File size error': '{0} je príliš veľký, nahrávajte súbory menšie ako {1}', 5 | 'Upload failed': '{0} sa nepodarilo nahrať', 6 | 'Per page': '{0} na stránku', 7 | 'Folder': 'Adresár', 8 | 'Login failed, please try again': 'Prihlásenie neúspešné, skúste to znova', 9 | 'Already logged in': 'Už ste prihlásený.', 10 | 'Please enter username and password': 'Zadajte prihlasovacie meno a heslo.', 11 | 'Not Found': 'Nenájdené', 12 | 'Not Allowed': 'Nepovolené', 13 | 'Please log in': 'Prihláste sa', 14 | 'Unknown error': 'Neznáma chyba', 15 | 'Add files': 'Pridať súbory', 16 | 'New': 'Nový', 17 | 'New name': 'Nové meno', 18 | 'Username': 'Prihlasovacie meno', 19 | 'Password': 'Heslo', 20 | 'Login': 'Prihlásiť sa', 21 | 'Logout': 'Odhlásiť sa', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Bez stránkovania', 24 | 'Time': 'Čas', 25 | 'Name': 'Meno', 26 | 'Size': 'Veľkosť', 27 | 'Home': 'Hlavný adresár', 28 | 'Copy': 'Kopírovať', 29 | 'Move': 'Presunúť', 30 | 'Rename': 'Premenovať', 31 | 'Required': 'Vyplňte toto pole', 32 | 'Zip': 'Archivovať do zip', 33 | 'Batch Download': 'Hromadné sťahovanie', 34 | 'Unzip': 'Rozbaliť zip archív', 35 | 'Delete': 'Vymazať', 36 | 'Download': 'Stiahnuť', 37 | 'Copy link': 'Skopírovať odkaz', 38 | 'Done': 'Hotovo', 39 | 'File': 'Súbor', 40 | 'Drop files to upload': 'Pre nahratie presuňte súbory sem', 41 | 'Close': 'Zavrieť', 42 | 'Select Folder': 'Vyberte adresár', 43 | 'Users': 'Používatelia', 44 | 'Files': 'Súbory', 45 | 'Role': 'Typ účtu', 46 | 'Cancel': 'Zrušiť', 47 | 'Paused': 'Pozastavené', 48 | 'Confirm': 'Potvrdiť', 49 | 'Create': 'Vytvoriť', 50 | 'User': 'Používateľ', 51 | 'Admin': 'Admin', 52 | 'Save': 'Uložiť', 53 | 'Read': 'Čítanie', 54 | 'Write': 'Zapisovanie', 55 | 'Upload': 'Nahrávanie', 56 | 'Permissions': 'Oprávnenia', 57 | 'Homedir': 'Hlavný adresár', 58 | 'Leave blank for no change': 'Ak nechcete zmeniť nechajte prázdne', 59 | 'Are you sure you want to do this?': 'Naozaj to chcete urobiť?', 60 | 'Are you sure you want to allow access to everyone?': 'Naozaj chcete povoliť prístup bez hesla?', 61 | 'Are you sure you want to stop all uploads?': 'Naozaj chcete zastaviť všetky nahrávania?', 62 | 'Something went wrong': 'Niečo sa pokazilo', 63 | 'Invalid directory': 'Neplatný adresár', 64 | 'This field is required': 'Toto pole je povinné', 65 | 'Username already taken': 'Toto prihlasovacie meno sa už používa', 66 | 'User not found': 'Používateľ sa nenašiel', 67 | 'Old password': 'Staré heslo', 68 | 'New password': 'Nové heslo', 69 | 'Wrong password': 'Zlé heslo', 70 | 'Updated': 'Aktualizované', 71 | 'Deleted': 'Vymazané', 72 | 'Your file is ready': 'Váš súbor je pripravený', 73 | 'View': 'Zobraziť', 74 | 'Search': 'Vyhľadávanie', 75 | 'Download permission': 'Sťahovanie', 76 | 'Guest': 'Hosť', 77 | 'Show hidden': 'Zobraziť skryté', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/spanish.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Seleccionados: {0} de {1}', 3 | 'Uploading files': 'Subiendo {0}% de {1}', 4 | 'File size error': '{0} es demasiado grande, por favor suba ficheros menores a {1}', 5 | 'Upload failed': '{0} no se pudo subir', 6 | 'Per page': '{0} por página', 7 | 'Folder': 'Carpeta', 8 | 'Login failed, please try again': 'Inicio de sesión incorrecto, por favor pruebe de nuevo', 9 | 'Already logged in': 'Ya había iniciado sesión.', 10 | 'Please enter username and password': 'Por favor, escriba nombre de usuario y contraseña.', 11 | 'Not Found': 'No encontrado', 12 | 'Not Allowed': 'No permitido', 13 | 'Please log in': 'Por favor, inicie sesión', 14 | 'Unknown error': 'Error desconocido', 15 | 'Add files': 'Añadir ficheros', 16 | 'New': 'Nuevo', 17 | 'New name': 'Nuevo nombre', 18 | 'Username': 'Nombre de usuario', 19 | 'Password': 'Contraseña', 20 | 'Login': 'Iniciar sesión', 21 | 'Logout': 'Salir', 22 | 'Profile': 'Perfil', 23 | 'No pagination': 'Sin paginación', 24 | 'Time': 'Fecha', 25 | 'Name': 'Nombre', 26 | 'Size': 'Tamaño', 27 | 'Home': 'Carpeta principal', 28 | 'Copy': 'Copiar', 29 | 'Move': 'Mover', 30 | 'Rename': 'Renombrar', 31 | 'Required': 'Por favor, rellene este campo', 32 | 'Zip': 'Comprimir', 33 | 'Batch Download': 'Descarga por lotes', 34 | 'Unzip': 'Descomprimir', 35 | 'Delete': 'Eliminar', 36 | 'Download': 'Descargar', 37 | 'Copy link': 'Copiar enlace', 38 | 'Done': 'Hecho', 39 | 'File': 'Archivo', 40 | 'Drop files to upload': 'Soltar archivos para subir', 41 | 'Close': 'Cerrar', 42 | 'Select Folder': 'Seleccionar carpeta', 43 | 'Users': 'Usuarios', 44 | 'Files': 'Ficheros', 45 | 'Role': 'Rol', 46 | 'Cancel': 'Cancelar', 47 | 'Paused': 'Pausado', 48 | 'Confirm': 'Confirmar', 49 | 'Create': 'Crear', 50 | 'User': 'Usuario', 51 | 'Admin': 'Administrador', 52 | 'Save': 'Guardar', 53 | 'Read': 'Leer', 54 | 'Write': 'Escribir', 55 | 'Upload': 'Subir', 56 | 'Permissions': 'Permisos', 57 | 'Homedir': 'Carpeta inicial', 58 | 'Leave blank for no change': 'Dejar en blanco para no cambiar', 59 | 'Are you sure you want to do this?': '¿Seguro que quiere hacer esto?', 60 | 'Are you sure you want to allow access to everyone?': '¿Seguro que quiere permitir el acceso a todo el mundo?', 61 | 'Are you sure you want to stop all uploads?': '¿Seguro que quiere parar todas las subidas?', 62 | 'Something went wrong': 'Algo ha ido mal', 63 | 'Invalid directory': 'Carpeta incorrecta', 64 | 'This field is required': 'Este campo es obligatorio', 65 | 'Username already taken': 'El nombre de usuario ya existe', 66 | 'User not found': 'Usuario no encontrado', 67 | 'Old password': 'Contraseña anterior', 68 | 'New password': 'Nueva contraseña', 69 | 'Wrong password': 'Contraseña incorrecta', 70 | 'Updated': 'Actualizado', 71 | 'Deleted': 'Eliminado', 72 | 'Your file is ready': 'Su fichero está listo', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'Descargar', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Mostrar oculto', 78 | } 79 | 80 | export default data 81 | -------------------------------------------------------------------------------- /frontend/translations/swedish.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Vald: {0} of {1}', 3 | 'Uploading files': 'Laddar upp {0}% of {1}', 4 | 'File size error': '{0} är för stor, max filstorlek är {1}', 5 | 'Upload failed': '{0} uppladdning misslyckades', 6 | 'Per page': '{0} Per sida', 7 | 'Folder': 'Mapp', 8 | 'Login failed, please try again': 'Inloggning misslyckades, försök igen.', 9 | 'Already logged in': 'Redan inloggad.', 10 | 'Please enter username and password': 'Ange användarnamn och lösenord.', 11 | 'Not Found': 'Ej funnen', 12 | 'Not Allowed': 'Ej tillåten', 13 | 'Please log in': 'Var vanlig logga in.', 14 | 'Unknown error': 'Okänt fel', 15 | 'Add files': 'Lägg till filer', 16 | 'New': 'Ny', 17 | 'New name': 'Nytt namn', 18 | 'Username': 'Användarnamn', 19 | 'Password': 'Lösenord', 20 | 'Login': 'Logga in', 21 | 'Logout': 'Logga ut', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Sidhantering', 24 | 'Time': 'Tid', 25 | 'Name': 'Namn', 26 | 'Size': 'Storlek', 27 | 'Home': 'Hem', 28 | 'Copy': 'Kopiera', 29 | 'Move': 'Flytta', 30 | 'Rename': 'Byt namn', 31 | 'Required': 'Vänligen fyll i detta fält', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Batch nedladdning', 34 | 'Unzip': 'Unzip', 35 | 'Delete': 'Borttag', 36 | 'Download': 'Ladda ned', 37 | 'Copy link': 'Kopiera länk', 38 | 'Done': 'Klar', 39 | 'File': 'Fil', 40 | 'Drop files to upload': 'Släpp filer för uppladdning', 41 | 'Close': 'Stäng', 42 | 'Select Folder': 'Välj mapp', 43 | 'Users': 'Användare', 44 | 'Files': 'Filer', 45 | 'Role': 'Roll', 46 | 'Cancel': 'Avbryt', 47 | 'Paused': 'Pausad', 48 | 'Confirm': 'Godkänn', 49 | 'Create': 'Skapa', 50 | 'User': 'Användare', 51 | 'Admin': 'Admin', 52 | 'Save': 'Spara', 53 | 'Read': 'Läs', 54 | 'Write': 'Skriv', 55 | 'Upload': 'Ladda upp', 56 | 'Permissions': 'Behörigheter', 57 | 'Homedir': 'Hem mapp', 58 | 'Leave blank for no change': 'Lämna blankt för ingen ändring', 59 | 'Are you sure you want to do this?': 'Är du säker på att du vill göra detta?', 60 | 'Are you sure you want to allow access to everyone?': 'Vill du verkligen ge access till alla?', 61 | 'Are you sure you want to stop all uploads?': 'Vill du stoppa alla uppladdningar?', 62 | 'Something went wrong': 'Något gick fel', 63 | 'Invalid directory': 'Ogiltig mapp', 64 | 'This field is required': 'Detta fält krävs', 65 | 'Username already taken': 'Användarnamnet finns redan', 66 | 'User not found': 'Användaren hittas inte', 67 | 'Old password': 'Gammalt lösenord', 68 | 'New password': 'Nytt lösenord', 69 | 'Wrong password': 'fel lösenord', 70 | 'Updated': 'Uppdaterad', 71 | 'Deleted': 'Borttagen', 72 | 'Your file is ready': 'Din fil är klar', 73 | 'View': 'Visa', 74 | 'Search': 'Sök', 75 | 'Download permission': 'Ladda ned', 76 | 'Guest': 'Gäst', 77 | 'Show hidden': 'Visa dold', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/translations/turkish.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | 'Selected': 'Seçilen: {0} - {1}', 3 | 'Uploading files': 'Yükleniyor {0}% - {1}', 4 | 'File size error': '{0} çok büyük, lütfen {1} den küçük dosya yükleyin', 5 | 'Upload failed': '{0} yüklenemedi', 6 | 'Per page': 'Sayfa başına {0} tane', 7 | 'Folder': 'Klasör', 8 | 'Login failed, please try again': 'Giriş başarısız. Lütfen tekrar deneyin', 9 | 'Already logged in': 'Zaten giriş yapılmış.', 10 | 'Please enter username and password': 'Lütfen kullanıcı adınızı ve şifrenizi giriniz.', 11 | 'Not Found': 'Bulunamadı', 12 | 'Not Allowed': 'İzin verilmedi', 13 | 'Please log in': 'Lütfen giriş yapın', 14 | 'Unknown error': 'Bilinmeyen hata', 15 | 'Add files': 'Dosya Ekle', 16 | 'New': 'Yeni', 17 | 'New name': 'Yeni Ad', 18 | 'Username': 'Kullanıcı Adı', 19 | 'Password': 'Parola', 20 | 'Login': 'Giriş', 21 | 'Logout': 'Çıkış', 22 | 'Profile': 'Profil', 23 | 'No pagination': 'Sayfa Yok', 24 | 'Time': 'Zaman', 25 | 'Name': 'Ad', 26 | 'Size': 'Boyut', 27 | 'Home': 'Anasayfa', 28 | 'Copy': 'Kopyala', 29 | 'Move': 'Taşı', 30 | 'Rename': 'Yeniden adlandır', 31 | 'Required': 'Lütfen bu alanı doldurun', 32 | 'Zip': 'Zip', 33 | 'Batch Download': 'Batch İndirme', 34 | 'Unzip': 'Zipi çıkart', 35 | 'Delete': 'Sil', 36 | 'Download': 'İndir', 37 | 'Copy link': 'Bağlantıyı Kopyala', 38 | 'Done': 'Tamam', 39 | 'File': 'Dosya', 40 | 'Drop files to upload': 'Yüklemek için dosyayı sürükle', 41 | 'Close': 'Kapat', 42 | 'Select Folder': 'Klasör Seç', 43 | 'Users': 'Kullanıcılar', 44 | 'Files': 'Dosyalar', 45 | 'Role': 'Rol', 46 | 'Cancel': 'İptal', 47 | 'Paused': 'Durduruldu', 48 | 'Confirm': 'Onayla', 49 | 'Create': 'Oluştur', 50 | 'User': 'Kullanıcı', 51 | 'Admin': 'Admin', 52 | 'Save': 'Kaydet', 53 | 'Read': 'Okuma', 54 | 'Write': 'Yazma', 55 | 'Upload': 'Yükleme', 56 | 'Permissions': 'İzimler', 57 | 'Homedir': 'Ana Klasör', 58 | 'Leave blank for no change': 'Değişiklik yapmamak için boş bırakın', 59 | 'Are you sure you want to do this?': 'Bunu yapmak istediğinizden emin misiniz?', 60 | 'Are you sure you want to allow access to everyone?': 'Herkese erişime izin vermek istediğinizinden emin misiniz?', 61 | 'Are you sure you want to stop all uploads?': 'Tüm yüklemeleri durdurmak istediğinizden emin misiniz?', 62 | 'Something went wrong': 'Bir şeyler yanlış gitti', 63 | 'Invalid directory': 'Geçersiz dizin', 64 | 'This field is required': 'Bu alan gereklidir', 65 | 'Username already taken': 'Kullanıcı adı önceden alınmış', 66 | 'User not found': 'Kullanıcı bulunamadı', 67 | 'Old password': 'Eski parola', 68 | 'New password': 'Yeni parola', 69 | 'Wrong password': 'parola hatalı', 70 | 'Updated': 'Güncellendi', 71 | 'Deleted': 'Silindi', 72 | 'Your file is ready': 'Dosyanız Hazır', 73 | 'View': 'View', 74 | 'Search': 'Search', 75 | 'Download permission': 'İndir', 76 | 'Guest': 'Guest', 77 | 'Show hidden': 'Gizlenenleri göster', 78 | } 79 | 80 | export default data 81 | 82 | -------------------------------------------------------------------------------- /frontend/views/Login.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 81 | 82 | 102 | -------------------------------------------------------------------------------- /frontend/views/partials/Editor.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 72 | 73 | 85 | -------------------------------------------------------------------------------- /frontend/views/partials/Gallery.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 51 | 52 | 86 | -------------------------------------------------------------------------------- /frontend/views/partials/Menu.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 85 | 86 | 110 | -------------------------------------------------------------------------------- /frontend/views/partials/Pagination.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 27 | 28 | -------------------------------------------------------------------------------- /frontend/views/partials/Profile.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 72 | -------------------------------------------------------------------------------- /frontend/views/partials/Search.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 102 | 103 | 105 | -------------------------------------------------------------------------------- /frontend/views/partials/Tree.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 31 | 32 | 42 | -------------------------------------------------------------------------------- /frontend/views/partials/TreeNode.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 78 | 79 | 85 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | /frontend/$1' 18 | }, 19 | snapshotSerializers: [ 20 | 'jest-serializer-vue' 21 | ], 22 | testMatch: [ 23 | '**/tests/frontend/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' 24 | ], 25 | testURL: 'http://localhost/' 26 | } 27 | -------------------------------------------------------------------------------- /linuxforcomposer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linuxforphp/linuxforcomposer", 3 | "description": "A Composer interface to run 'Linux for PHP' Docker containers, Dockerfiles or docker-compose files.", 4 | "single": { 5 | "image": { 6 | "linuxforcomposer": { 7 | "php-versions": [ 8 | "8.0" 9 | ], 10 | "script": [ 11 | "lfphp-get --force node.js-10", 12 | "npm update -g", 13 | "composer self-update", 14 | "pip install --upgrade pip", 15 | "pip install sphinx==5.3.0", 16 | "pip install urllib3==1.26.15", 17 | "cd /srv/filebrowser", 18 | "chmod -R 775 private/", 19 | "chmod -R 775 repository/", 20 | "cp -f configuration_sample.php configuration.php", 21 | "composer install", 22 | "cd /srv", 23 | "mv www www.OLD", 24 | "ln -s filebrowser/dist www", 25 | "groupadd vagrant", 26 | "useradd -p 'vagrant' -g vagrant vagrant", 27 | "cp -rf /etc/skel /home/vagrant", 28 | "chown -R vagrant:vagrant /home/vagrant", 29 | "echo 'vagrant:vagrant' | chpasswd", 30 | "chown -R vagrant:apache filebrowser", 31 | "cd filebrowser", 32 | "npm install", 33 | "npm run build", 34 | "cd /srv", 35 | "chown -R vagrant:apache filebrowser", 36 | "lfphp --phpfpm --apache" 37 | ], 38 | "thread-safe": "false" 39 | }, 40 | "dockerfile": { 41 | "url": "", 42 | "container-name": "", 43 | "username": "", 44 | "token": "" 45 | } 46 | }, 47 | "containers": { 48 | "modes": { 49 | "mode1": "detached", 50 | "mode2": "interactive", 51 | "mode3": "tty" 52 | }, 53 | "ports": { 54 | "port1": [ 55 | "8181:80" 56 | ] 57 | }, 58 | "volumes": { 59 | "volume1": "${PWD}/:/srv/filebrowser" 60 | }, 61 | "persist-data": { 62 | "mount": "false", 63 | "root-name": "", 64 | "directories": { 65 | "directory1": "", 66 | "directory2": "", 67 | "directory3": "" 68 | } 69 | } 70 | } 71 | }, 72 | "docker-compose": { 73 | "url": "", 74 | "username": "", 75 | "token": "" 76 | }, 77 | "lfphp-cloud": { 78 | "account": "", 79 | "username": "", 80 | "token": "" 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filebrowser", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "concurrently \"php -S localhost:8081\" \"vue-cli-service serve\"", 7 | "build": "vue-cli-service build --no-clean", 8 | "test:unit": "vue-cli-service test:unit", 9 | "test:e2e": "vue-cli-service test:e2e --headless", 10 | "lint": "vue-cli-service lint --no-fix frontend/", 11 | "e2e": "vue-cli-service test:e2e" 12 | }, 13 | "dependencies": { 14 | "core-js": "^3.6.5", 15 | "js-base64": "^2.5.2", 16 | "prismjs": "^1.20.0", 17 | "vue-lazyload": "^1.3.3", 18 | "vue-prism-editor": "^0.5.1" 19 | }, 20 | "devDependencies": { 21 | "@fortawesome/fontawesome-free": "^5.13.0", 22 | "@vue/cli-plugin-babel": "^4.3.1", 23 | "@vue/cli-plugin-e2e-cypress": "^4.3.1", 24 | "@vue/cli-plugin-eslint": "^4.3.1", 25 | "@vue/cli-plugin-unit-jest": "^4.3.1", 26 | "@vue/cli-service": "^4.3.1", 27 | "@vue/test-utils": "1.0.0-beta.29", 28 | "axios": "^0.21.1", 29 | "babel-core": "7.0.0-bridge.0", 30 | "babel-eslint": "^10.1.0", 31 | "babel-jest": "^24.9.0", 32 | "buefy": "^0.7.10", 33 | "concurrently": "^4.1.2", 34 | "eslint": "^5.16.0", 35 | "eslint-plugin-vue": "^5.0.0", 36 | "node-sass": "^4.14.1", 37 | "resumablejs": "^1.1.0", 38 | "sass-loader": "^7.3.1", 39 | "vue": "^2.6.11", 40 | "vue-clipboard2": "^0.3.1", 41 | "vue-router": "^3.1.6", 42 | "vue-template-compiler": "^2.6.11", 43 | "vuex": "^3.4.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/backend/Unit 14 | 15 | 16 | 17 | ./tests/backend/Feature 18 | 19 | 20 | 21 | 22 | ./backend 23 | 24 | ./backend/View.php 25 | ./config/services.config.php 26 | ./config/routes.config.php 27 | ./config/routes.optional.config.php 28 | 29 | 30 | 31 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /private/.gitignore: -------------------------------------------------------------------------------- 1 | /tmp 2 | /users.json 3 | -------------------------------------------------------------------------------- /private/.htaccess: -------------------------------------------------------------------------------- 1 | deny from all 2 | -------------------------------------------------------------------------------- /private/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /private/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /private/users.json.blank: -------------------------------------------------------------------------------- 1 | {"1":{"username":"admin","name":"Admin","role":"admin","homedir":"\/","permissions":"read|write|upload|download|batchdownload|zip","password":"$2y$10$Nu35w4pteLfc7BDCIkDPkecjw8wsH8Y2GMfIewUbXLT7zzW6WOxwq"},"2":{"username":"guest","name":"Guest","role":"guest","homedir":"\/","permissions":"","password":""}} 2 | -------------------------------------------------------------------------------- /repository/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /robots.txt: -------------------------------------------------------------------------------- 1 | # No crawling for robots, also present in the header as meta tag. 2 | # Remove if you want to appear on google search 3 | 4 | User-agent: * 5 | Disallow: / 6 | 7 | -------------------------------------------------------------------------------- /tests/backend/FakeResponse.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests; 13 | 14 | use Filebrowser\Kernel\Response; 15 | 16 | class FakeResponse extends Response 17 | { 18 | public function send() 19 | { 20 | // do nothing 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/backend/FakeStreamedResponse.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests; 13 | 14 | use Filebrowser\Kernel\StreamedResponse; 15 | 16 | class FakeStreamedResponse extends StreamedResponse 17 | { 18 | public function send() 19 | { 20 | // do nothing 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/backend/Feature/AppTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Kernel\Response; 16 | use Filebrowser\Services\Auth\AuthInterface; 17 | use Filebrowser\Services\Session\SessionStorageInterface; 18 | use Tests\TestCase; 19 | 20 | /** 21 | * @internal 22 | */ 23 | class AppTest extends TestCase 24 | { 25 | public function testAppWithoutSession() 26 | { 27 | $app = $this->bootFreshApp(); 28 | 29 | $request = $app->resolve(Request::class); 30 | $response = $app->resolve(Response::class); 31 | $session = $app->resolve(SessionStorageInterface::class); 32 | $auth = $app->resolve(AuthInterface::class); 33 | 34 | $this->assertNotNull($request); 35 | $this->assertNotNull($response); 36 | $this->assertNotNull($session); 37 | $this->assertNull($auth->user()); 38 | } 39 | 40 | public function testAppWithSession() 41 | { 42 | // first login request 43 | $request1 = Request::create( 44 | '?r=/login', 45 | 'POST', 46 | [], 47 | [], 48 | [], 49 | [ 50 | 'CONTENT_TYPE' => 'application/json', 51 | 'HTTP_ACCEPT' => 'application/json', 52 | ], 53 | '{"username":"admin@example.com","password":"admin123"}' 54 | ); 55 | 56 | $config = $this->getMockConfig(); 57 | 58 | $this->bootFreshApp($config, $request1, null, true); 59 | $prev_session = $request1->getSession(); 60 | 61 | // another request with previous session 62 | $request2 = Request::create( 63 | '?r=/', 64 | 'GET' 65 | ); 66 | $request2->setSession($prev_session); 67 | 68 | $app2 = $this->bootFreshApp($config, $request2); 69 | 70 | $auth = $app2->resolve(AuthInterface::class); 71 | 72 | $this->assertNotNull($auth->user()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/backend/Feature/FeatureTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Feature; 13 | 14 | use Tests\TestCase; 15 | 16 | /** 17 | * @internal 18 | */ 19 | class FeatureTest extends TestCase 20 | { 21 | public function testHome() 22 | { 23 | $this->sendRequest('GET', '/'); 24 | 25 | $this->assertOk(); 26 | } 27 | 28 | public function testMethodNotAllowed() 29 | { 30 | $this->sendRequest('DELETE', '/'); 31 | 32 | $this->assertStatus(401); 33 | } 34 | 35 | public function testNotFoundPage() 36 | { 37 | $this->sendRequest('GET', '/fakeroute'); 38 | 39 | $this->assertStatus(404); 40 | } 41 | 42 | public function testUnprocessableRequest() 43 | { 44 | $this->sendRequest('POST', '/login', 'dddddd'); 45 | 46 | $this->assertUnprocessable(); 47 | } 48 | 49 | public function testGetFrontendConfig() 50 | { 51 | $this->sendRequest('GET', '/getconfig'); 52 | 53 | $this->assertOk(); 54 | $this->assertResponseJsonHas([ 55 | 'data' => [ 56 | 'app_name' => 'FileBrowser', 57 | 'upload_max_size' => 2 * 1024 * 1024, 58 | 'upload_chunk_size' => 1 * 1024 * 1024, 59 | 'upload_simultaneous' => 3, 60 | ], 61 | ]); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/backend/MockUsers.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests; 13 | 14 | use Filebrowser\Services\Auth\Adapters\JsonFile; 15 | use Filebrowser\Services\Auth\AuthInterface; 16 | use Filebrowser\Services\Auth\User; 17 | use Filebrowser\Services\Service; 18 | 19 | class MockUsers extends JsonFile implements Service, AuthInterface 20 | { 21 | private $users_array = []; 22 | 23 | public function init(array $config = []) 24 | { 25 | $this->addMockUsers(); 26 | } 27 | 28 | protected function getUsers(): array 29 | { 30 | return $this->users_array; 31 | } 32 | 33 | protected function saveUsers(array $users) 34 | { 35 | return $this->users_array = $users; 36 | } 37 | 38 | public function user(): ?User 39 | { 40 | return $this->session ? $this->session->get(self::SESSION_KEY, null) : null; 41 | } 42 | 43 | 44 | private function addMockUsers() 45 | { 46 | $guest = new User(); 47 | $guest->setRole('guest'); 48 | $guest->setHomedir('/'); 49 | $guest->setUsername('guest'); 50 | $guest->setName('Guest'); 51 | $guest->setPermissions([]); 52 | 53 | $admin = new User(); 54 | $admin->setRole('admin'); 55 | $admin->setHomedir('/'); 56 | $admin->setUsername('admin@example.com'); 57 | $admin->setName('Admin'); 58 | $admin->setPermissions(['read', 'write', 'upload', 'download', 'batchdownload', 'zip']); 59 | 60 | $john = new User(); 61 | $john->setRole('user'); 62 | $john->setHomedir('/john'); 63 | $john->setUsername('john@example.com'); 64 | $john->setName('John Doe'); 65 | $john->setPermissions(['read', 'write', 'upload', 'download', 'batchdownload']); 66 | 67 | $jane = new User(); 68 | $jane->setRole('user'); 69 | $jane->setHomedir('/jane'); 70 | $jane->setUsername('jane@example.com'); 71 | $jane->setName('Jane Doe'); 72 | $jane->setPermissions(['read', 'write']); 73 | 74 | $this->add($guest, ''); 75 | $this->add($admin, 'admin123'); 76 | $this->add($john, 'john123'); 77 | $this->add($jane, 'jane123'); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /tests/backend/Unit/Auth/DatabaseAuthTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit\Auth; 13 | 14 | use Filebrowser\Services\Auth\Adapters\Database; 15 | 16 | /** 17 | * @internal 18 | */ 19 | class DatabaseAuthTest extends AuthTest 20 | { 21 | protected $conn; 22 | 23 | public function setAuth() 24 | { 25 | $this->auth = new Database($this->session); 26 | $this->auth->init([ 27 | 'driver' => 'sqlite', 28 | 'dsn' => 'sqlite::memory:', 29 | 'database' => 'tests/backend/tmp/temp/sqlite', 30 | ]); 31 | 32 | $this->conn = $this->auth->getConnection(); 33 | 34 | $this->conn->query('DROP TABLE IF EXISTS [users]'); 35 | $this->conn->query('CREATE TABLE [users] ( 36 | [id] INTEGER PRIMARY KEY NOT NULL, 37 | [username] VARCHAR(255) NOT NULL, 38 | [name] VARCHAR(255) NOT NULL, 39 | [role] VARCHAR(20) NOT NULL, 40 | [permissions] VARCHAR(100) NOT NULL, 41 | [homedir] VARCHAR(1000) NOT NULL, 42 | [password] VARCHAR(255) NOT NULL 43 | 44 | )'); 45 | $this->conn->fetch('SELECT * FROM users WHERE username = ?', 'admin'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/backend/Unit/Auth/JsonAuthTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit\Auth; 13 | 14 | use Filebrowser\Services\Auth\Adapters\JsonFile; 15 | 16 | /** 17 | * @internal 18 | */ 19 | class JsonFileTest extends AuthTest 20 | { 21 | private $mock_file = TEST_DIR.'/mockusers.json'; 22 | 23 | protected function tearDown(): void 24 | { 25 | @unlink($this->mock_file); 26 | @unlink($this->mock_file.'.blank'); 27 | } 28 | 29 | public function setAuth() 30 | { 31 | @unlink($this->mock_file); 32 | @touch($this->mock_file.'.blank'); 33 | 34 | $this->auth = new JsonFile($this->session); 35 | $this->auth->init([ 36 | 'file' => $this->mock_file, 37 | ]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/backend/Unit/ConfigTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Filebrowser\Config\Config; 15 | use Tests\TestCase; 16 | 17 | /** 18 | * @internal 19 | */ 20 | class ConfigTest extends TestCase 21 | { 22 | public function testGettingAnItemFromConfigUsingDotNotation() 23 | { 24 | $sample = [ 25 | 'test' => 'something', 26 | 'test2' => [ 27 | 'deep' => 123, 28 | ], 29 | 'test3' => [ 30 | 'sub' => [ 31 | 'subsub' => 2, 32 | ], 33 | ], 34 | ]; 35 | 36 | $config = new Config($sample); 37 | 38 | $this->assertEquals($sample, $config->get()); 39 | $this->assertEquals('something', $config->get('test')); 40 | $this->assertEquals(123, $config->get('test2.deep')); 41 | $this->assertEquals(2, $config->get('test3.sub.subsub')); 42 | $this->assertNull($config->get('not-found')); 43 | $this->assertEquals('default', $config->get('not-found', 'default')); 44 | $this->assertEquals('default', $config->get('not.found', 'default')); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/backend/Unit/MainTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Filebrowser\App; 15 | use Filebrowser\Config\Config; 16 | use Filebrowser\Container\Container; 17 | use Filebrowser\Kernel\Request; 18 | use Filebrowser\Kernel\Response; 19 | use Tests\FakeResponse; 20 | use Tests\FakeStreamedResponse; 21 | use Tests\TestCase; 22 | 23 | /** 24 | * @internal 25 | */ 26 | class MainTest extends TestCase 27 | { 28 | public function testMainApp() 29 | { 30 | $config = new Config(); 31 | $request = new Request(); 32 | $response = new FakeResponse(); 33 | $sresponse = new FakeStreamedResponse(); 34 | $container = new Container(); 35 | 36 | $app = new App($config, $request, $response, $sresponse, $container); 37 | 38 | $this->assertEquals($config, $app->resolve(Config::class)); 39 | $this->assertEquals($request, $app->resolve(Request::class)); 40 | $this->assertInstanceOf(Response::class, $app->resolve(Response::class)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/backend/Unit/SessionStorageTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Filebrowser\Kernel\Request; 15 | use Filebrowser\Services\Session\Adapters\SessionStorage; 16 | use Tests\TestCase; 17 | 18 | /** 19 | * @internal 20 | */ 21 | class SessionStorageTest extends TestCase 22 | { 23 | protected $session_service; 24 | 25 | protected function setUp(): void 26 | { 27 | $this->session_service = new SessionStorage(new Request()); 28 | $this->session_service->init([ 29 | 'handler' => function () { 30 | return new \Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage(); 31 | }, 32 | ]); 33 | 34 | parent::setUp(); 35 | } 36 | 37 | public function testInvalidateSession() 38 | { 39 | $this->session_service->set('test1', 444); 40 | $this->session_service->invalidate(); 41 | 42 | $this->assertNull($this->session_service->get('test1')); 43 | } 44 | 45 | public function testInvalidateSessionWhichIsNotStartedYet() 46 | { 47 | $this->session_service->invalidate(); 48 | 49 | $this->assertNull($this->session_service->get('something')); 50 | } 51 | 52 | public function testUseSession() 53 | { 54 | $this->session_service->set('test2', 999); 55 | $this->session_service->save(); 56 | 57 | $this->assertEquals(999, $this->session_service->get('test2')); 58 | $this->assertNull($this->session_service->get('test1')); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /tests/backend/Unit/SymfonyProcessFactoryTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Filebrowser\Services\Process\SymfonyProcessFactory; 15 | use Tests\TestCase; 16 | 17 | /** 18 | * @internal 19 | */ 20 | class SymfonyProcessFactoryTest extends TestCase 21 | { 22 | public function testCreatingASymfonyProcessWithSuccess() 23 | { 24 | $command[] = '/bin/true'; 25 | $symfonyProcess = (new SymfonyProcessFactory())->createService($command); 26 | $symfonyProcess->start(); 27 | 28 | while ($symfonyProcess->isRunning()) { 29 | // waiting for process to finish 30 | } 31 | 32 | $this->assertEquals('Symfony\Component\Process\Process', get_class($symfonyProcess)); 33 | $this->assertEquals('\'/bin/true\'', $symfonyProcess->getCommandLine()); 34 | $this->assertTrue($symfonyProcess->isSuccessful()); 35 | $this->assertEquals(0, $symfonyProcess->getExitCode()); 36 | } 37 | 38 | public function testCreatingASymfonyProcessWithFailure() 39 | { 40 | // Intended error 41 | $command[] = 'zip -r ' . TEST_DIR . DIR_SEP . 'fail.zip foo.txt bar.txt baz.txt'; 42 | 43 | $symfonyProcess = (new SymfonyProcessFactory())->createService($command); 44 | 45 | $this->assertEquals('Symfony\Component\Process\Process', get_class($symfonyProcess)); 46 | $this->assertStringContainsString('zip -r', $symfonyProcess->getCommandLine()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/backend/Unit/ViewTest.php: -------------------------------------------------------------------------------- 1 | 7 | * Copyright 2018-2021, Milos Stojanovic 8 | * 9 | * For the full copyright and license information, please view the LICENSE file 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Filebrowser\Config\Config; 15 | use Filebrowser\Services\View\Adapters\Vuejs; 16 | use Tests\TestCase; 17 | 18 | /** 19 | * @internal 20 | */ 21 | class ViewTest extends TestCase 22 | { 23 | public function testViewService() 24 | { 25 | $config_mock = new Config(['frontend_config' => ['app_name' => 'testapp']]); 26 | 27 | $service = new Vuejs($config_mock); 28 | $service->init(); 29 | 30 | $this->assertRegexp('/testapp/', $service->getIndexPage()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/backend/tmp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !testarchive.zip 4 | -------------------------------------------------------------------------------- /tests/backend/tmp/testarchive.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/tests/backend/tmp/testarchive.zip -------------------------------------------------------------------------------- /tests/config/testroutesoptional.php: -------------------------------------------------------------------------------- 1 | [ 7 | 'POST', '/zipitems', '\Filebrowser\Controllers\FileController@zipItemsProc', 8 | ], 9 | 'roles' => [ 10 | 'guest', 'user', 'admin', 11 | ], 12 | 'permissions' => [ 13 | 'read', 'write', 'zip', 14 | ], 15 | ], 16 | [ 17 | 'route' => [ 18 | 'POST', '/unzipitem', '\Filebrowser\Controllers\FileController@unzipItemProc', 19 | ], 20 | 'roles' => [ 21 | 'guest', 'user', 'admin', 22 | ], 23 | 'permissions' => [ 24 | 'read', 'write', 'zip', 25 | ], 26 | ], 27 | [ 28 | 'route' => [ 29 | 'POST', '/batchdownload', '\Filebrowser\Controllers\DownloadController@batchDownloadCreateProc', 30 | ], 31 | 'roles' => [ 32 | 'guest', 'user', 'admin', 33 | ], 34 | 'permissions' => [ 35 | 'read', 'download', 'batchdownload', 36 | ], 37 | ], 38 | ]; 39 | } else { 40 | return [ 41 | [ 42 | 'route' => [ 43 | 'POST', '/zipitems', '\Filebrowser\Controllers\FileController@zipItems', 44 | ], 45 | 'roles' => [ 46 | 'guest', 'user', 'admin', 47 | ], 48 | 'permissions' => [ 49 | 'read', 'write', 'zip', 50 | ], 51 | ], 52 | [ 53 | 'route' => [ 54 | 'POST', '/unzipitem', '\Filebrowser\Controllers\FileController@unzipItem', 55 | ], 56 | 'roles' => [ 57 | 'guest', 'user', 'admin', 58 | ], 59 | 'permissions' => [ 60 | 'read', 'write', 'zip', 61 | ], 62 | ], 63 | [ 64 | 'route' => [ 65 | 'POST', '/batchdownload', '\Filebrowser\Controllers\DownloadController@batchDownloadCreate', 66 | ], 67 | 'roles' => [ 68 | 'guest', 'user', 'admin', 69 | ], 70 | 'permissions' => [ 71 | 'read', 'download', 'batchdownload', 72 | ], 73 | ], 74 | ]; 75 | } 76 | -------------------------------------------------------------------------------- /tests/frontend/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 4 | -------------------------------------------------------------------------------- /tests/frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | 'extends': [ 7 | 'plugin:vue/essential', 8 | 'eslint:recommended' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/frontend/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxforphp/filebrowser/e00c12fa5e9a71479d718b3037626c0881d0e9f4/tests/frontend/.gitignore -------------------------------------------------------------------------------- /tests/frontend/e2e/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'cypress' 4 | ], 5 | env: { 6 | mocha: true, 7 | 'cypress/globals': true 8 | }, 9 | rules: { 10 | strict: 'off' 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/dir_home.json: -------------------------------------------------------------------------------- 1 | {"data":{"location":"\/","files":[{"type":"dir","path":"\/Folder","name":"Folder","size":0,"time":1561107605},{"type":"dir","path":"\/My Documents","name":"My Documents","size":0,"time":1561111756},{"type":"dir","path":"\/Projects","name":"Projects","size":0,"time":1560583678},{"type":"dir","path":"\/Test","name":"Test","size":0,"time":1561108206},{"type":"file","path":"\/Brochure.pdf","name":"Brochure.pdf","size":70646,"time":1561112785},{"type":"file","path":"\/compressed.zip","name":"compressed.zip","size":217,"time":1561107915},{"type":"file","path":"\/english.js","name":"english.js","size":2434,"time":1560581859},{"type":"file","path":"\/logo.png","name":"logo.png","size":13638,"time":1560581761},{"type":"file","path":"\/read_only_demo.txt","name":"read_only_demo.txt","size":31,"time":1561107677}]}} 2 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/dir_mydocs.json: -------------------------------------------------------------------------------- 1 | {"data":{"location":"\/My Documents","files":[{"type":"back","path":"\/","name":"..","size":0,"time":0},{"type":"file","path":"\/My Documents\/Cool Project.doc","name":"Cool Project.doc","size":13638,"time":1560583727},{"type":"file","path":"\/My Documents\/Document-1.doc","name":"Document-1.doc","size":13638,"time":1560583594},{"type":"file","path":"\/My Documents\/Document-2.doc","name":"Document-2.doc","size":13638,"time":1560583597},{"type":"file","path":"\/My Documents\/logo.png","name":"logo.png","size":13638,"time":1560583532}]}} 2 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/getconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "app_name": "FileBrowser", 4 | "app_version": "7.0.0", 5 | "language": "english", 6 | "logo": "", 7 | "upload_max_size": 104857600, 8 | "upload_chunk_size": 1048576, 9 | "upload_simultaneous": 3, 10 | "default_archive_name": "archive.zip", 11 | "editable": [".txt",".css",".js",".ts",".html",".php"], 12 | "date_format": "YY/MM/DD hh:mm:ss", 13 | "guest_redirection": "" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/getuser.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "role": "guest", 4 | "permissions": [ 5 | "read", 6 | "write", 7 | "upload", 8 | "download", 9 | "batchdownload", 10 | "zip" 11 | ], 12 | "homedir": "\\/", 13 | "username": "guest", 14 | "name": "Guest" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/listusers.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": [ 3 | { 4 | "role": "admin", 5 | "permissions": [ 6 | "read", 7 | "write", 8 | "upload", 9 | "download", 10 | "batchdownload", 11 | "zip" 12 | ], 13 | "homedir": "\/", 14 | "username": "admin", 15 | "name": "Admin" 16 | }, 17 | { 18 | "role": "guest", 19 | "permissions": [ 20 | "read", 21 | "write", 22 | "upload", 23 | "download", 24 | "batchdownload", 25 | "zip" 26 | ], 27 | "homedir": "\/", 28 | "username": "guest", 29 | "name": "Guest" 30 | }, 31 | { 32 | "role": "user", 33 | "permissions": [ 34 | "read", 35 | "write", 36 | "upload", 37 | "download", 38 | "batchdownload", 39 | "zip" 40 | ], 41 | "homedir": "\/", 42 | "username": "john", 43 | "name": "john" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/login_admin.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "role": "admin", 4 | "permissions": [ 5 | "read", 6 | "write", 7 | "upload", 8 | "download", 9 | "batchdownload", 10 | "zip" 11 | ], 12 | "homedir": "\/", 13 | "username": "admin", 14 | "name": "Admin" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/frontend/e2e/fixtures/login_user.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "role": "user", 4 | "permissions": [ 5 | "read", 6 | "write", 7 | "upload", 8 | "download", 9 | "batchdownload", 10 | "zip" 11 | ], 12 | "homedir": "\/", 13 | "username": "john", 14 | "name": "John" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /tests/frontend/e2e/plugins/index.js: -------------------------------------------------------------------------------- 1 | // https://docs.cypress.io/guides/guides/plugins-guide.html 2 | 3 | // if you need a custom webpack configuration you can uncomment the following import 4 | // and then use the `file:preprocessor` event 5 | // as explained in the cypress docs 6 | // https://docs.cypress.io/api/plugins/preprocessors-api.html#Examples 7 | 8 | /* eslint-disable import/no-extraneous-dependencies, global-require, arrow-body-style */ 9 | // const webpack = require('@cypress/webpack-preprocessor') 10 | 11 | module.exports = (on, config) => { 12 | // on('file:preprocessor', webpack({ 13 | // webpackOptions: require('@vue/cli-service/webpack.config'), 14 | // watchOptions: {} 15 | // })) 16 | 17 | return Object.assign({}, config, { 18 | fixturesFolder: 'tests/frontend/e2e/fixtures', 19 | integrationFolder: 'tests/frontend/e2e/specs', 20 | screenshotsFolder: 'tests/frontend/e2e/screenshots', 21 | videosFolder: 'tests/frontend/e2e/videos', 22 | supportFile: 'tests/frontend/e2e/support/index.js' 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /tests/frontend/e2e/support/commands.js: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // 11 | // 12 | // -- This is a parent command -- 13 | // Cypress.Commands.add("login", (email, password) => { ... }) 14 | // 15 | // 16 | // -- This is a child command -- 17 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 18 | // 19 | // 20 | // -- This is a dual command -- 21 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 22 | // 23 | // 24 | // -- This is will overwrite an existing command -- 25 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 26 | -------------------------------------------------------------------------------- /tests/frontend/e2e/support/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') 21 | -------------------------------------------------------------------------------- /tests/frontend/unit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | jest: true 4 | } 5 | } -------------------------------------------------------------------------------- /tests/frontend/unit/example.spec.js: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils' 2 | import HelloWorld from '@/components/HelloWorld.vue' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('renders props.msg when passed', () => { 6 | const msg = 'new message' 7 | const wrapper = shallowMount(HelloWorld, { 8 | propsData: { msg } 9 | }) 10 | expect(wrapper.text()).toMatch(msg) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | indexPath: 'main.html', 3 | filenameHashing: false, 4 | configureWebpack: config => { 5 | config.entry = { 6 | app: [ 7 | './frontend/main.js' 8 | ] 9 | } 10 | } 11 | } 12 | --------------------------------------------------------------------------------