From e9e7c68557b2d54b51185771aa092f0f259ee680 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 2 Jul 2025 07:39:01 +0200 Subject: [PATCH 001/266] chore: remove symlink in Dockerfile --- docker/alpine/init.sh | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/docker/alpine/init.sh b/docker/alpine/init.sh index 209757d8..4dc5908a 100755 --- a/docker/alpine/init.sh +++ b/docker/alpine/init.sh @@ -2,37 +2,6 @@ set -e -# Backwards compatibility for old Docker image -if [ -f "/.filebrowser.json" ]; then - ln -s /.filebrowser.json /config/settings.json - - echo "" - echo "!!!!!!!!!!!!!!!!!!!!! IMPORTANT INFORMATION !!!!!!!!!!!!!!!!!!!!!" - echo "Symlinking /.filebrowser.json to /config/settings.json for backwards compatibility." - echo "" - echo "The volume mount configuration has changed in the latest release." - echo "Please rename .filebrowser.json to settings.json and mount the parent directory to /config". - echo "Read more on https://filebrowser.org/installation.html#docker" - echo "" - echo "This workaround will be removed in a future release." - echo "" -fi - -# Backwards compatibility for old Docker image -if [ -f "/database.db" ]; then - ln -s /database.db /database/filebrowser.db - - echo "" - echo "!!!!!!!!!!!!!!!!!!!!! IMPORTANT INFORMATION !!!!!!!!!!!!!!!!!!!!!" - echo "" - echo "The volume mount configuration has changed in the latest release." - echo "Please rename database.db to filebrowser.db and mount the parent directory to /database". - echo "Read more on https://filebrowser.org/installation.html#docker" - echo "" - echo "This workaround will be removed in a future release." - echo "" -fi - # Ensure configuration exists if [ ! -f "/config/settings.json" ]; then cp -a /defaults/settings.json /config/settings.json From 9da01be7fc34eeae4a2d0518645769d2614dd554 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 2 Jul 2025 07:45:39 +0200 Subject: [PATCH 002/266] docs: add update instructions to Docker --- www/docs/installation.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/www/docs/installation.md b/www/docs/installation.md index 05e1b5b4..08c6248d 100644 --- a/www/docs/installation.md +++ b/www/docs/installation.md @@ -74,6 +74,23 @@ Both `settings.json` and `filebrowser.db` will automatically be initialized if t File Browser is now up and running. Read some [first boot](#first-boot) for more information. +> [!NOTE] +> +> The Alpine Docker image has breaking changes from v2.33.0, in order to address multiple issues that have continuously affected multiple users. The changes are as follows: +> +> - **User**: File Browser no longer runs as `root`, but as user with PID 1000 and GID 1000. You can still change this by using Docker's [`--user` flag](https://www.docker.com/blog/understanding-the-docker-user-instruction/). +> - **Volumes**: the volumes with the database and configuration are now aligned with the s6-overlay images. Instead of mounting the files themselves, which leads to frequent issues, you now mount the surrounding directory. +> +> Assuming you have a `database.db`, a `.filebrowser.json` and the data in `/data`, do the following: +> +> 1. Change the path of `database` in `.filebrowser.json` to `/database/filebrowser.db` +> 2. Rename `database.db` to `filebrowser.db` +> 3. Rename `.filebrowser.json` to `settings.json` +> 4. Put them in the same directory locally, let's say `/app/filebrowser/` +> 5. Change the permissions of both directories: `sudo chown -R 1000:1000 /app/filebrowser /data` +> 6. Mount with the flags `-v /app/filebrowser:/database -v /app/filebrowser:/config` - you can also choose to put them in separate directories, but it is not needed. + + ## First Boot Your instance is now up and running. File Browser will automatically bootstrap a database, in which the configuration and the users are stored. You can find the address in which your instance is running, as well as the randomly generated password for the user `admin`, in the console logs. From fae410ce6e7727ee7dab63479a6f08eec15fe5a4 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 2 Jul 2025 08:26:36 +0200 Subject: [PATCH 003/266] docs: improve custom branding info --- www/docs/configuration.md | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/www/docs/configuration.md b/www/docs/configuration.md index 2b7299e3..a7fb6cb3 100644 --- a/www/docs/configuration.md +++ b/www/docs/configuration.md @@ -4,41 +4,45 @@ Most of the configuration can be understood through our Command Line Interface d ## Custom Branding -You are able to customize your File Browser installation by changing its name to any other you want, by adding a global custom style sheet and by using your own logotype if you want. To address this, there are three configuration options that can be changed: +You can customize File Browser to use your own branding. This includes the following: -* **Name:** which is the instance name that will show up on login and signup pages. This won't replace the version message in the sidebar. -* **Disable external links:** this will disable any external links (except the ones to this documentation). -* **Folder:** is the path to a directory that can contain two items: - * **custom.css**, containing the styles you want to apply to your installation. - * **img** a directory whose files can replace the [default logotypes](https://github.com/filebrowser/filebrowser/tree/master/frontend/public/img) in the application. +- **Name**: the name of the instance that shows up on the tab title, login pages, and some other places. +- **Disable External Links**: disables all external links, except to the documentation. +- **Disable Used Percentage**: disables the disk usage information on the sidebar. +- **Branding Folder**: directory which can contain two items: + - `custom.css`, containing a global stylesheet to apply to all users. + - `img`, a directory which can replace all the [default logotypes](https://github.com/filebrowser/filebrowser/tree/master/frontend/public/img) from the application. -These options can be either set via the CLI interface using the following command: +This can be configured by the administrator user, under **Settings → Global Settings**. You can also update the configuration directly using the CLI: ```sh filebrowser config set --branding.name "My Name" \ --branding.files "/abs/path/to/my/dir" \ --branding.disableExternal ``` -Or can be set under 'Branding directory path' in **Settings → Global Settings**. > [!NOTE] > -> If using Docker then remember to bind this directory, for example as `/home/username/containers/filebrowser/branding:/branding` +> If you are using Docker, you need to mount a volume with the `branding` directory in order for it to be accessible from within the container. -For custom icons to be recognized you need to create `img` and `img/icons` directories and place the svg in the `branding/img` directory: +### Custom Icons + +To replace the default logotype and favicons, you need to create an `img` directory under the branding directory. The structure of this directory must mimic the one from the [default logotypes](https://github.com/filebrowser/filebrowser/tree/master/frontend/public/img): ``` -- filebrowser - - branding - - img - - icons - - logo.svg - - filebrowser.db +img/ + logo.svg + icons/ + favicon.ico + favicon.svg + (...) ``` -To replace the favicon you need to place this in the `img/icons` directory but also note that some of the other PNG icon types will be required too (see the default logotypes link above) as the browser will normally use the highest resolution option available (at a minimum the 16x16 and 32x32 options). You can use the [Real Favicon Generator](https://realfavicongenerator.net/) to generate these for you from your base image. +Note that there are different versions of the same favicon in multiple sizes. To replace all of them, you need to add versions for all of them. You can use the [Real Favicon Generator](https://realfavicongenerator.net/) to generate these for you from your base image. -The icons are cached, to make the new ones appear more quickly open developer tools in your browser, then click on the Application tab, then Storage and then 'Clear Site Data'. +> [!NOTE] +> +> The icons are cached by the browser, so you may not see your changes immediately. You can address this by clearing your browser's cache. ## Authentication Method From 04166e81e52d38b1f66ba3313ccb1291c239eea2 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 2 Jul 2025 08:29:27 +0200 Subject: [PATCH 004/266] feat: update icons, remove deprecated Microsoft Tiles --- frontend/index.html | 29 ++---------- .../public/img/icons/apple-touch-icon.png | Bin 7420 -> 8540 bytes frontend/public/img/icons/browserconfig.xml | 9 ---- frontend/public/img/icons/favicon-16x16.png | Bin 843 -> 0 bytes frontend/public/img/icons/favicon-32x32.png | Bin 1250 -> 0 bytes frontend/public/img/icons/favicon.ico | Bin 15086 -> 15086 bytes frontend/public/img/icons/favicon.svg | 3 ++ frontend/public/img/icons/mstile-144x144.png | Bin 7213 -> 0 bytes frontend/public/img/icons/mstile-150x150.png | Bin 7022 -> 0 bytes frontend/public/img/icons/mstile-310x150.png | Bin 7644 -> 0 bytes frontend/public/img/icons/mstile-310x310.png | Bin 14508 -> 0 bytes frontend/public/img/icons/mstile-70x70.png | Bin 5005 -> 0 bytes .../public/img/icons/safari-pinned-tab.svg | 42 ------------------ frontend/public/index.html | 35 ++------------- 14 files changed, 11 insertions(+), 107 deletions(-) delete mode 100644 frontend/public/img/icons/browserconfig.xml delete mode 100644 frontend/public/img/icons/favicon-16x16.png delete mode 100644 frontend/public/img/icons/favicon-32x32.png create mode 100644 frontend/public/img/icons/favicon.svg delete mode 100644 frontend/public/img/icons/mstile-144x144.png delete mode 100644 frontend/public/img/icons/mstile-150x150.png delete mode 100644 frontend/public/img/icons/mstile-310x150.png delete mode 100644 frontend/public/img/icons/mstile-310x310.png delete mode 100644 frontend/public/img/icons/mstile-70x70.png delete mode 100644 frontend/public/img/icons/safari-pinned-tab.svg diff --git a/frontend/index.html b/frontend/index.html index 02c303ae..3b54dcdf 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -10,18 +10,10 @@ File Browser - - + + + + - - - - - - - - - - diff --git a/go.mod b/go.mod index 90e05b2b..504fadae 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/maruel/natural v1.1.1 github.com/marusama/semaphore/v2 v2.5.0 - github.com/mholt/archiver/v3 v3.5.1 + github.com/mholt/archives v0.1.3 github.com/mitchellh/go-homedir v1.1.0 github.com/pelletier/go-toml/v2 v2.2.4 github.com/shirou/gopsutil/v3 v3.24.5 @@ -32,11 +32,15 @@ require ( ) require ( - github.com/andybalholm/brotli v1.1.1 // indirect + github.com/STARRY-S/zip v0.2.1 // indirect + github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect github.com/asticode/go-astikit v0.55.0 // indirect github.com/asticode/go-astits v1.13.0 // indirect + github.com/bodgit/plumbing v1.3.0 // indirect + github.com/bodgit/sevenzip v1.6.0 // indirect + github.com/bodgit/windows v1.0.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect @@ -45,21 +49,27 @@ require ( github.com/go-viper/mapstructure/v2 v2.3.0 // indirect github.com/golang/geo v0.0.0-20250606134707-e8fe6a72b492 // indirect github.com/golang/snappy v1.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect - github.com/nwaples/rardecode v1.1.3 // indirect + github.com/mikelolasagasti/xz v1.0.1 // indirect + github.com/minio/minlz v1.0.0 // indirect + github.com/nwaples/rardecode/v2 v2.1.0 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/sagikazarmark/locafero v0.9.0 // indirect + github.com/sorairolake/lzip-go v0.3.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/cast v1.9.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/ulikunitz/xz v0.5.12 // indirect - github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/multierr v1.11.0 // indirect + go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/net v0.41.0 // indirect golang.org/x/sys v0.33.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 27e66a86..fa589357 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,30 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/STARRY-S/zip v0.2.1 h1:pWBd4tuSGm3wtpoqRZZ2EAwOmcHK6XFf7bU9qcJXyFg= +github.com/STARRY-S/zip v0.2.1/go.mod h1:xNvshLODWtC4EJ702g7cTYn13G53o1+X9BWnPFpcWV4= github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM= github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM= -github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= -github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 h1:8PmGpDEZl9yDpcdEr6Odf23feCxK3LNUNMxjXg41pZQ= +github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac= github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0= github.com/asticode/go-astikit v0.20.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0= @@ -16,6 +36,17 @@ github.com/asticode/go-astisub v0.34.0/go.mod h1:WTkuSzFB+Bp7wezuSf2Oxulj5A8zu2z github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ= github.com/asticode/go-astits v1.13.0 h1:XOgkaadfZODnyZRR5Y0/DWkA9vrkLLPLeeOvDwfKZ1c= github.com/asticode/go-astits v1.13.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI= +github.com/bodgit/plumbing v1.3.0 h1:pf9Itz1JOQgn7vEOE7v7nlEfBykYqvUYioC61TwWCFU= +github.com/bodgit/plumbing v1.3.0/go.mod h1:JOTb4XiRu5xfnmdnDJo6GmSbSbtSyufrsyZFByMtKEs= +github.com/bodgit/sevenzip v1.6.0 h1:a4R0Wu6/P1o1pP/3VV++aEOcyeBxeO/xE2Y9NSTrr6A= +github.com/bodgit/sevenzip v1.6.0/go.mod h1:zOBh9nJUof7tcrlqJFv1koWRrhz3LbDbUNngkuZxLMc= +github.com/bodgit/windows v1.0.1 h1:tF7K6KOluPYygXa3Z2594zxlkbKPAOvqr97etrGNIz4= +github.com/bodgit/windows v1.0.1/go.mod h1:a6JLwrB4KrTR5hBpp8FI9/9W9jJfeQ2h4XDXU74ZCdM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -23,8 +54,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= -github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= -github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 h1:2tV76y6Q9BB+NEBasnqvs7e49aEBFI8ejC89PSnWH+4= +github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E= github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8= @@ -43,6 +74,8 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20221003142440-7a1927d49d9d/go.mod h1:LV github.com/dsoprea/go-utility/v2 v2.0.0-20221003160719-7bc88537c05e/go.mod h1:VZ7cB0pTjm1ADBWhJUOHESu4ZYy9JN+ZPqjfiW09EPU= github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 h1:DilThiXje0z+3UQ5YjYiSRRzVdtamFpvBQXKwMglWqw= github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4GC5sXji84i/p+irqghpPFZBF8tRN/Q7+700G0/DLe8= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -55,6 +88,8 @@ github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWE github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -67,30 +102,63 @@ github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgR github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= github.com/golang/geo v0.0.0-20250606134707-e8fe6a72b492 h1:8mHyM6CCmj/DQAhHXJVTgdkg/6hAH71N7qGEF+t4Bzg= github.com/golang/geo v0.0.0-20250606134707-e8fe6a72b492/go.mod h1:Vaw7L5b+xa3Rj4/pRtrQkymn3lSBRB/NAEdbF9YEVLA= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -105,16 +173,18 @@ github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM= github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= -github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= -github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4= +github.com/mholt/archives v0.1.3 h1:aEAaOtNra78G+TvV5ohmXrJOAzf++dIlYeDW3N9q458= +github.com/mholt/archives v0.1.3/go.mod h1:LUCGp++/IbV/I0Xq4SzcIR6uwgeh2yjnQWamjRQfLTU= +github.com/mikelolasagasti/xz v1.0.1 h1:Q2F2jX0RYJUG3+WsM+FJknv+6eVjsjXNDV0KJXZzkD0= +github.com/mikelolasagasti/xz v1.0.1/go.mod h1:muAirjiOUxPRXwm9HdDtB3uoRPrGnL85XHtokL9Hcgc= +github.com/minio/minlz v1.0.0 h1:Kj7aJZ1//LlTP1DM8Jm7lNKvvJS2m74gyyXXn3+uJWQ= +github.com/minio/minlz v1.0.0/go.mod h1:qT0aEB35q79LLornSzeDH75LBf3aH1MV+jB5w9Wasec= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= -github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= -github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nwaples/rardecode/v2 v2.1.0 h1:JQl9ZoBPDy+nIZGb1mx8+anfHp/LV3NE2MjMiv0ct/U= +github.com/nwaples/rardecode/v2 v2.1.0/go.mod h1:7uz379lSxPe6j9nvzxUZ+n7mnJNgjsRNb6IbvGVHRmw= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE= @@ -123,13 +193,18 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= +github.com/sorairolake/lzip-go v0.3.5 h1:ms5Xri9o1JBIWvOFAorYtUNik6HI3HgBTkISiqu0Cwg= +github.com/sorairolake/lzip-go v0.3.5/go.mod h1:N0KYq5iWrMXI0ZEXKXaS9hCyOjZUQdBDEIbXfoUwbdk= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= @@ -143,8 +218,13 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= @@ -152,69 +232,210 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= -github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.4.1 h1:5mOV+HWjIPLEAlUGMsveaUvK2+byZMFOzojoi7bh7uI= go.etcd.io/bbolt v1.4.1/go.mod h1:c8zu2BnXWTu2XM4XcICtbGSl9cFwsXtcf9zLt2OncM8= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go4.org v0.0.0-20230225012048-214862532bf5 h1:nifaUDeh+rPaBCMPMQHZmvJf+QdpLFnuQPwx+LxVmtc= +go4.org v0.0.0-20230225012048-214862532bf5/go.mod h1:F57wTi5Lrj6WLyswp5EYV1ncrEbFGHD4hhz6S1ZYeaU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE= golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200320220750-118fecf932d8/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -222,5 +443,14 @@ gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/http/raw.go b/http/raw.go index cd05a1bc..cbddad59 100644 --- a/http/raw.go +++ b/http/raw.go @@ -2,6 +2,7 @@ package http import ( "errors" + "io/fs" "log" "net/http" "net/url" @@ -9,7 +10,7 @@ import ( "path/filepath" "strings" - "github.com/mholt/archiver/v3" + "github.com/mholt/archives" "github.com/filebrowser/filebrowser/v2/files" "github.com/filebrowser/filebrowser/v2/fileutils" @@ -44,22 +45,26 @@ func parseQueryFiles(r *http.Request, f *files.FileInfo, _ *users.User) ([]strin return fileSlice, nil } -func parseQueryAlgorithm(r *http.Request) (string, archiver.Writer, error) { +func parseQueryAlgorithm(r *http.Request) (string, archives.Archival, error) { switch r.URL.Query().Get("algo") { case "zip", "true", "": - return ".zip", archiver.NewZip(), nil + return ".zip", archives.Zip{}, nil case "tar": - return ".tar", archiver.NewTar(), nil + return ".tar", archives.Tar{}, nil case "targz": - return ".tar.gz", archiver.NewTarGz(), nil + return ".tar.gz", archives.CompressedArchive{Compression: archives.Gz{}, Archival: archives.Tar{}}, nil case "tarbz2": - return ".tar.bz2", archiver.NewTarBz2(), nil + return ".tar.bz2", archives.CompressedArchive{Compression: archives.Bz2{}, Archival: archives.Tar{}}, nil case "tarxz": - return ".tar.xz", archiver.NewTarXz(), nil + return ".tar.xz", archives.CompressedArchive{Compression: archives.Xz{}, Archival: archives.Tar{}}, nil case "tarlz4": - return ".tar.lz4", archiver.NewTarLz4(), nil + return ".tar.lz4", archives.CompressedArchive{Compression: archives.Lz4{}, Archival: archives.Tar{}}, nil case "tarsz": - return ".tar.sz", archiver.NewTarSz(), nil + return ".tar.sz", archives.CompressedArchive{Compression: archives.Sz{}, Archival: archives.Tar{}}, nil + case "tarbr": + return ".tar.br", archives.CompressedArchive{Compression: archives.Brotli{}, Archival: archives.Tar{}}, nil + case "tarzst": + return ".tar.zst", archives.CompressedArchive{Compression: archives.Zstd{}, Archival: archives.Tar{}}, nil default: return "", nil, errors.New("format not implemented") } @@ -103,57 +108,55 @@ var rawHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) return rawDirHandler(w, r, d, file) }) -func addFile(ar archiver.Writer, d *data, path, commonPath string) error { +func getFiles(d *data, path, commonPath string) ([]archives.FileInfo, error) { if !d.Check(path) { - return nil + return nil, nil } info, err := d.user.Fs.Stat(path) if err != nil { - return err + return nil, err } - if !info.IsDir() && !info.Mode().IsRegular() { - return nil - } - - file, err := d.user.Fs.Open(path) - if err != nil { - return err - } - defer file.Close() + var archiveFiles []archives.FileInfo if path != commonPath { - filename := strings.TrimPrefix(path, commonPath) - filename = strings.TrimPrefix(filename, string(filepath.Separator)) - err = ar.Write(archiver.File{ - FileInfo: archiver.FileInfo{ - FileInfo: info, - CustomName: filename, + nameInArchive := strings.TrimPrefix(path, commonPath) + nameInArchive = strings.TrimPrefix(nameInArchive, string(filepath.Separator)) + + archiveFiles = append(archiveFiles, archives.FileInfo{ + FileInfo: info, + NameInArchive: nameInArchive, + Open: func() (fs.File, error) { + return d.user.Fs.Open(path) }, - ReadCloser: file, }) - if err != nil { - return err - } } if info.IsDir() { - names, err := file.Readdirnames(0) + f, err := d.user.Fs.Open(path) if err != nil { - return err + return nil, err + } + defer f.Close() + + names, err := f.Readdirnames(0) + if err != nil { + return nil, err } for _, name := range names { fPath := filepath.Join(path, name) - err = addFile(ar, d, fPath, commonPath) + subFiles, err := getFiles(d, fPath, commonPath) if err != nil { - log.Printf("Failed to archive %s: %v", fPath, err) + log.Printf("Failed to get files from %s: %v", fPath, err) + continue } + archiveFiles = append(archiveFiles, subFiles...) } } - return nil + return archiveFiles, nil } func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files.FileInfo) (int, error) { @@ -162,27 +165,28 @@ func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files. return http.StatusInternalServerError, err } - extension, ar, err := parseQueryAlgorithm(r) + extension, archiver, err := parseQueryAlgorithm(r) if err != nil { return http.StatusInternalServerError, err } - err = ar.Create(w) - if err != nil { - return http.StatusInternalServerError, err - } - defer ar.Close() - commonDir := fileutils.CommonPrefix(filepath.Separator, filenames...) + var allFiles []archives.FileInfo + for _, fname := range filenames { + archiveFiles, err := getFiles(d, fname, commonDir) + if err != nil { + log.Printf("Failed to get files from %s: %v", fname, err) + continue + } + allFiles = append(allFiles, archiveFiles...) + } + name := filepath.Base(commonDir) if name == "." || name == "" || name == string(filepath.Separator) { - // Not sure when/if this will ever be true, though kept incase there is an edge-case where it is if file.Name != "" { name = file.Name } else { - // This should indicate that the fs root is the directory being downloaded, lookup its name - actual, statErr := file.Fs.Stat(".") if statErr != nil { return http.StatusInternalServerError, statErr @@ -190,19 +194,14 @@ func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files. name = actual.Name() } } - // Prefix used to distinguish a filelist generated - // archive from the full directory archive if len(filenames) > 1 { name = "_" + name } name += extension w.Header().Set("Content-Disposition", "attachment; filename*=utf-8''"+url.PathEscape(name)) - for _, fname := range filenames { - err = addFile(ar, d, fname, commonDir) - if err != nil { - log.Printf("Failed to archive %s: %v", fname, err) - } + if err := archiver.Archive(r.Context(), w, allFiles); err != nil { + return http.StatusInternalServerError, err } return 0, nil From 0f27c91eca581482ce4f82f6429f5dac12f8b64e Mon Sep 17 00:00:00 2001 From: Ramires Viana <59319979+ramiresviana@users.noreply.github.com> Date: Sun, 13 Jul 2025 03:16:01 -0300 Subject: [PATCH 030/266] fix: drop modify permission for uploading new file (#5270) --- frontend/src/api/tus.ts | 47 ++++----- frontend/src/stores/upload.ts | 23 ++--- frontend/src/types/upload.d.ts | 8 -- go.mod | 2 + go.sum | 2 + http/http.go | 2 +- http/tus_handlers.go | 179 ++++++++++++++++++++++++++++++--- 7 files changed, 197 insertions(+), 66 deletions(-) diff --git a/frontend/src/api/tus.ts b/frontend/src/api/tus.ts index 5e4e116b..64efe69a 100644 --- a/frontend/src/api/tus.ts +++ b/frontend/src/api/tus.ts @@ -3,7 +3,6 @@ import { baseURL, tusEndpoint, tusSettings } from "@/utils/constants"; import { useAuthStore } from "@/stores/auth"; import { useUploadStore } from "@/stores/upload"; import { removePrefix } from "@/api/utils"; -import { fetchURL } from "./utils"; const RETRY_BASE_DELAY = 1000; const RETRY_MAX_DELAY = 20000; @@ -28,8 +27,6 @@ export async function upload( filePath = removePrefix(filePath); const resourcePath = `${tusEndpoint}${filePath}?override=${overwrite}`; - await createUpload(resourcePath); - const authStore = useAuthStore(); // Exit early because of typescript, tus content can't be a string @@ -38,7 +35,7 @@ export async function upload( } return new Promise((resolve, reject) => { const upload = new tus.Upload(content, { - uploadUrl: `${baseURL}${resourcePath}`, + endpoint: `${baseURL}${resourcePath}`, chunkSize: tusSettings.chunkSize, retryDelays: computeRetryDelays(tusSettings), parallelUploads: 1, @@ -46,6 +43,18 @@ export async function upload( headers: { "X-Auth": authStore.jwt, }, + onShouldRetry: function (err) { + const status = err.originalResponse + ? err.originalResponse.getStatus() + : 0; + + // Do not retry for file conflict. + if (status === 409) { + return false; + } + + return true; + }, onError: function (error) { if (CURRENT_UPLOAD_LIST[filePath].interval) { clearInterval(CURRENT_UPLOAD_LIST[filePath].interval); @@ -92,17 +101,6 @@ export async function upload( }); } -async function createUpload(resourcePath: string) { - const headResp = await fetchURL(resourcePath, { - method: "POST", - }); - if (headResp.status !== 201) { - throw new Error( - `Failed to create an upload: ${headResp.status} ${headResp.statusText}` - ); - } -} - function computeRetryDelays(tusSettings: TusSettings): number[] | undefined { if (!tusSettings.retryCount || tusSettings.retryCount < 1) { // Disable retries altogether @@ -130,7 +128,8 @@ function isTusSupported() { return tus.isSupported === true; } -function computeETA(state: ETAState, speed?: number) { +function computeETA(speed?: number) { + const state = useUploadStore(); if (state.speedMbyte === 0) { return Infinity; } @@ -138,22 +137,13 @@ function computeETA(state: ETAState, speed?: number) { (acc: number, size: number) => acc + size, 0 ); - const uploadedSize = state.progress.reduce( - (acc: number, progress: Progress) => { - if (typeof progress === "number") { - return acc + progress; - } - return acc; - }, - 0 - ); + const uploadedSize = state.progress.reduce((a, b) => a + b, 0); const remainingSize = totalSize - uploadedSize; const speedBytesPerSecond = (speed ?? state.speedMbyte) * 1024 * 1024; return remainingSize / speedBytesPerSecond; } function computeGlobalSpeedAndETA() { - const uploadStore = useUploadStore(); let totalSpeed = 0; let totalCount = 0; @@ -165,7 +155,7 @@ function computeGlobalSpeedAndETA() { if (totalCount === 0) return { speed: 0, eta: Infinity }; const averageSpeed = totalSpeed / totalCount; - const averageETA = computeETA(uploadStore, averageSpeed); + const averageETA = computeETA(averageSpeed); return { speed: averageSpeed, eta: averageETA }; } @@ -207,6 +197,9 @@ export function abortAllUploads() { } if (CURRENT_UPLOAD_LIST[filePath].upload) { CURRENT_UPLOAD_LIST[filePath].upload.abort(true); + CURRENT_UPLOAD_LIST[filePath].upload.options!.onError!( + new Error("Upload aborted") + ); } delete CURRENT_UPLOAD_LIST[filePath]; } diff --git a/frontend/src/stores/upload.ts b/frontend/src/stores/upload.ts index d9698255..8429146e 100644 --- a/frontend/src/stores/upload.ts +++ b/frontend/src/stores/upload.ts @@ -30,7 +30,7 @@ export const useUploadStore = defineStore("upload", { state: (): { id: number; sizes: number[]; - progress: Progress[]; + progress: number[]; queue: UploadItem[]; uploads: Uploads; speedMbyte: number; @@ -54,9 +54,7 @@ export const useUploadStore = defineStore("upload", { } const totalSize = state.sizes.reduce((a, b) => a + b, 0); - - // TODO: this looks ugly but it works with ts now - const sum = state.progress.reduce((acc, val) => +acc + +val) as number; + const sum = state.progress.reduce((a, b) => a + b, 0); return Math.ceil((sum / totalSize) * 100); }, getProgressDecimal: (state) => { @@ -65,21 +63,14 @@ export const useUploadStore = defineStore("upload", { } const totalSize = state.sizes.reduce((a, b) => a + b, 0); - - // TODO: this looks ugly but it works with ts now - const sum = state.progress.reduce((acc, val) => +acc + +val) as number; + const sum = state.progress.reduce((a, b) => a + b, 0); return ((sum / totalSize) * 100).toFixed(2); }, getTotalProgressBytes: (state) => { if (state.progress.length === 0 || state.sizes.length === 0) { return "0 Bytes"; } - const sum = state.progress.reduce( - (sum, p, i) => - (sum as number) + - (typeof p === "number" ? p : p ? state.sizes[i] : 0), - 0 - ) as number; + const sum = state.progress.reduce((a, b) => a + b, 0); return formatSize(sum); }, getTotalSize: (state) => { @@ -104,7 +95,7 @@ export const useUploadStore = defineStore("upload", { const isDir = upload.file.isDir; const progress = isDir ? 100 - : Math.ceil(((state.progress[id] as number) / size) * 100); + : Math.ceil((state.progress[id] / size) * 100); files.push({ id, @@ -124,7 +115,7 @@ export const useUploadStore = defineStore("upload", { }, actions: { // no context as first argument, use `this` instead - setProgress({ id, loaded }: { id: number; loaded: Progress }) { + setProgress({ id, loaded }: { id: number; loaded: number }) { this.progress[id] = loaded; }, setError(error: Error) { @@ -168,7 +159,7 @@ export const useUploadStore = defineStore("upload", { this.processUploads(); }, finishUpload(item: UploadItem) { - this.setProgress({ id: item.id, loaded: item.file.size > 0 }); + this.setProgress({ id: item.id, loaded: item.file.size }); this.removeJob(item.id); this.processUploads(); }, diff --git a/frontend/src/types/upload.d.ts b/frontend/src/types/upload.d.ts index 263b6bf5..131f4b2c 100644 --- a/frontend/src/types/upload.d.ts +++ b/frontend/src/types/upload.d.ts @@ -28,8 +28,6 @@ interface UploadEntry { type UploadList = UploadEntry[]; -type Progress = number | boolean; - type CurrentUploadList = { [key: string]: { upload: import("tus-js-client").Upload; @@ -43,9 +41,3 @@ type CurrentUploadList = { interval: number | undefined; }; }; - -interface ETAState { - sizes: number[]; - progress: Progress[]; - speedMbyte: number; -} diff --git a/go.mod b/go.mod index 504fadae..09a12662 100644 --- a/go.mod +++ b/go.mod @@ -53,6 +53,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jellydator/ttlcache/v3 v3.4.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/pgzip v1.2.6 // indirect github.com/mikelolasagasti/xz v1.0.1 // indirect @@ -71,6 +72,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/net v0.41.0 // indirect + golang.org/x/sync v0.15.0 // indirect golang.org/x/sys v0.33.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index fa589357..8e5e336c 100644 --- a/go.sum +++ b/go.sum @@ -150,6 +150,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY= +github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= diff --git a/http/http.go b/http/http.go index 620c43fd..2d87535f 100644 --- a/http/http.go +++ b/http/http.go @@ -69,7 +69,7 @@ func NewHandler( api.PathPrefix("/tus").Handler(monkey(tusPostHandler(), "/api/tus")).Methods("POST") api.PathPrefix("/tus").Handler(monkey(tusHeadHandler(), "/api/tus")).Methods("HEAD", "GET") api.PathPrefix("/tus").Handler(monkey(tusPatchHandler(), "/api/tus")).Methods("PATCH") - api.PathPrefix("/tus").Handler(monkey(resourceDeleteHandler(fileCache), "/api/tus")).Methods("DELETE") + api.PathPrefix("/tus").Handler(monkey(tusDeleteHandler(), "/api/tus")).Methods("DELETE") api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET") diff --git a/http/tus_handlers.go b/http/tus_handlers.go index 7a3254ae..c5eec9ad 100644 --- a/http/tus_handlers.go +++ b/http/tus_handlers.go @@ -1,6 +1,7 @@ package http import ( + "context" "errors" "fmt" "io" @@ -8,14 +9,76 @@ import ( "os" "path/filepath" "strconv" + "time" + "github.com/jellydator/ttlcache/v3" "github.com/spf13/afero" "github.com/filebrowser/filebrowser/v2/files" ) +const maxUploadWait = 3 * time.Minute + +// Tracks active uploads along with their respective upload lengths +var activeUploads = initActiveUploads() + +func initActiveUploads() *ttlcache.Cache[string, int64] { + cache := ttlcache.New[string, int64]() + cache.OnEviction(func(_ context.Context, reason ttlcache.EvictionReason, item *ttlcache.Item[string, int64]) { + if reason == ttlcache.EvictionReasonExpired { + fmt.Printf("deleting incomplete upload file: \"%s\"", item.Key()) + os.Remove(item.Key()) + } + }) + go cache.Start() + + return cache +} + +func registerUpload(filePath string, fileSize int64) { + activeUploads.Set(filePath, fileSize, maxUploadWait) +} + +func completeUpload(filePath string) { + activeUploads.Delete(filePath) +} + +func getActiveUploadLength(filePath string) (int64, error) { + item := activeUploads.Get(filePath) + if item == nil { + return 0, fmt.Errorf("no active upload found for the given path") + } + + return item.Value(), nil +} + +func keepUploadActive(filePath string) func() { + stop := make(chan bool) + + go func() { + ticker := time.NewTicker(2 * time.Second) + defer ticker.Stop() + + for { + select { + case <-stop: + return + case <-ticker.C: + activeUploads.Touch(filePath) + } + } + }() + + return func() { + close(stop) + } +} + func tusPostHandler() handleFunc { - return withUser(func(_ http.ResponseWriter, r *http.Request, d *data) (int, error) { + return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { + if !d.user.Perm.Create || !d.Check(r.URL.Path) { + return http.StatusForbidden, nil + } file, err := files.NewFileInfo(&files.FileOptions{ Fs: d.user.Fs, Path: r.URL.Path, @@ -26,10 +89,6 @@ func tusPostHandler() handleFunc { }) switch { case errors.Is(err, afero.ErrFileNotFound): - if !d.user.Perm.Create || !d.Check(r.URL.Path) { - return http.StatusForbidden, nil - } - dirPath := filepath.Dir(r.URL.Path) if _, statErr := d.user.Fs.Stat(dirPath); os.IsNotExist(statErr) { if mkdirErr := d.user.Fs.MkdirAll(dirPath, files.PermDir); mkdirErr != nil { @@ -41,25 +100,55 @@ func tusPostHandler() handleFunc { } fileFlags := os.O_CREATE | os.O_WRONLY - if r.URL.Query().Get("override") == "true" { - fileFlags |= os.O_TRUNC - } // if file exists if file != nil { if file.IsDir { return http.StatusBadRequest, fmt.Errorf("cannot upload to a directory %s", file.RealPath()) } + + // Existing files will remain untouched unless explicitly instructed to override + if r.URL.Query().Get("override") != "true" { + return http.StatusConflict, nil + } + + // Permission for overwriting the file + if !d.user.Perm.Modify { + return http.StatusForbidden, nil + } + + fileFlags |= os.O_TRUNC } openFile, err := d.user.Fs.OpenFile(r.URL.Path, fileFlags, files.PermFile) if err != nil { return errToStatus(err), err } - if err := openFile.Close(); err != nil { + defer openFile.Close() + + file, err = files.NewFileInfo(&files.FileOptions{ + Fs: d.user.Fs, + Path: r.URL.Path, + Modify: d.user.Perm.Modify, + Expand: false, + ReadHeader: false, + Checker: d, + Content: false, + }) + if err != nil { return errToStatus(err), err } + uploadLength, err := getUploadLength(r) + if err != nil { + return http.StatusBadRequest, fmt.Errorf("invalid upload length: %w", err) + } + + // Enables the user to utilize the PATCH endpoint for uploading file data + registerUpload(file.RealPath(), uploadLength) + + w.Header().Set("Location", "/api/tus/"+r.URL.Path) + return http.StatusCreated, nil }) } @@ -67,7 +156,7 @@ func tusPostHandler() handleFunc { func tusHeadHandler() handleFunc { return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { w.Header().Set("Cache-Control", "no-store") - if !d.Check(r.URL.Path) { + if !d.user.Perm.Create || !d.Check(r.URL.Path) { return http.StatusForbidden, nil } @@ -83,8 +172,13 @@ func tusHeadHandler() handleFunc { return errToStatus(err), err } + uploadLength, err := getActiveUploadLength(file.RealPath()) + if err != nil { + return http.StatusNotFound, err + } + w.Header().Set("Upload-Offset", strconv.FormatInt(file.Size, 10)) - w.Header().Set("Upload-Length", "-1") + w.Header().Set("Upload-Length", strconv.FormatInt(uploadLength, 10)) return http.StatusOK, nil }) @@ -92,7 +186,7 @@ func tusHeadHandler() handleFunc { func tusPatchHandler() handleFunc { return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { - if !d.user.Perm.Modify || !d.Check(r.URL.Path) { + if !d.user.Perm.Create || !d.Check(r.URL.Path) { return http.StatusForbidden, nil } if r.Header.Get("Content-Type") != "application/offset+octet-stream" { @@ -101,7 +195,7 @@ func tusPatchHandler() handleFunc { uploadOffset, err := getUploadOffset(r) if err != nil { - return http.StatusBadRequest, fmt.Errorf("invalid upload offset: %w", err) + return http.StatusBadRequest, fmt.Errorf("invalid upload offset") } file, err := files.NewFileInfo(&files.FileOptions{ @@ -120,6 +214,15 @@ func tusPatchHandler() handleFunc { return errToStatus(err), err } + uploadLength, err := getActiveUploadLength(file.RealPath()) + if err != nil { + return http.StatusNotFound, err + } + + // Prevent the upload from being evicted during the transfer + stop := keepUploadActive(file.RealPath()) + defer stop() + switch { case file.IsDir: return http.StatusBadRequest, fmt.Errorf("cannot upload to a directory %s", file.RealPath()) @@ -148,12 +251,60 @@ func tusPatchHandler() handleFunc { return http.StatusInternalServerError, fmt.Errorf("could not write to file: %w", err) } - w.Header().Set("Upload-Offset", strconv.FormatInt(uploadOffset+bytesWritten, 10)) + newOffset := uploadOffset + bytesWritten + w.Header().Set("Upload-Offset", strconv.FormatInt(newOffset, 10)) + + if newOffset >= uploadLength { + completeUpload(file.RealPath()) + _ = d.RunHook(func() error { return nil }, "upload", r.URL.Path, "", d.user) + } return http.StatusNoContent, nil }) } +func tusDeleteHandler() handleFunc { + return withUser(func(_ http.ResponseWriter, r *http.Request, d *data) (int, error) { + if r.URL.Path == "/" || !d.user.Perm.Create { + return http.StatusForbidden, nil + } + + file, err := files.NewFileInfo(&files.FileOptions{ + Fs: d.user.Fs, + Path: r.URL.Path, + Modify: d.user.Perm.Modify, + Expand: false, + ReadHeader: d.server.TypeDetectionByHeader, + Checker: d, + }) + if err != nil { + return errToStatus(err), err + } + + _, err = getActiveUploadLength(file.RealPath()) + if err != nil { + return http.StatusNotFound, err + } + + err = d.user.Fs.RemoveAll(r.URL.Path) + if err != nil { + return errToStatus(err), err + } + + completeUpload(file.RealPath()) + + return http.StatusNoContent, nil + }) +} + +func getUploadLength(r *http.Request) (int64, error) { + uploadOffset, err := strconv.ParseInt(r.Header.Get("Upload-Length"), 10, 64) + if err != nil { + return 0, fmt.Errorf("invalid upload length: %w", err) + } + return uploadOffset, nil +} + func getUploadOffset(r *http.Request) (int64, error) { uploadOffset, err := strconv.ParseInt(r.Header.Get("Upload-Offset"), 10, 64) if err != nil { From 5a8e7171b1b41eff771fe27133c91d2c250896a8 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sun, 13 Jul 2025 08:18:06 +0200 Subject: [PATCH 031/266] fix: Settings button in the sidebar --- frontend/src/components/Sidebar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Sidebar.vue b/frontend/src/components/Sidebar.vue index 93cda311..74fb45ad 100644 --- a/frontend/src/components/Sidebar.vue +++ b/frontend/src/components/Sidebar.vue @@ -41,7 +41,7 @@
@@ -81,6 +88,7 @@ import { useAuthStore } from "@/stores/auth"; import { useLayoutStore } from "@/stores/layout"; import { users as api } from "@/api"; +import AceEditorTheme from "@/components/settings/AceEditorTheme.vue"; import Languages from "@/components/settings/Languages.vue"; import { computed, inject, onMounted, ref } from "vue"; import { useI18n } from "vue-i18n"; @@ -98,6 +106,7 @@ const hideDotfiles = ref(false); const singleClick = ref(false); const dateFormat = ref(false); const locale = ref(""); +const aceEditorTheme = ref(""); const passwordClass = computed(() => { const baseClass = "input input--block"; @@ -113,13 +122,14 @@ const passwordClass = computed(() => { return `${baseClass} input--red`; }); -onMounted(() => { +onMounted(async () => { layoutStore.loading = true; if (authStore.user === null) return false; locale.value = authStore.user.locale; hideDotfiles.value = authStore.user.hideDotfiles; singleClick.value = authStore.user.singleClick; dateFormat.value = authStore.user.dateFormat; + aceEditorTheme.value = authStore.user.aceEditorTheme; layoutStore.loading = false; return true; }); @@ -163,6 +173,7 @@ const updateSettings = async (event: Event) => { hideDotfiles: hideDotfiles.value, singleClick: singleClick.value, dateFormat: dateFormat.value, + aceEditorTheme: aceEditorTheme.value, }; await api.update(data, [ @@ -170,6 +181,7 @@ const updateSettings = async (event: Event) => { "hideDotfiles", "singleClick", "dateFormat", + "aceEditorTheme", ]); authStore.updateUser(data); $showSuccess(t("settings.settingsUpdated")); diff --git a/http/auth.go b/http/auth.go index 0ecaed14..62d6779e 100644 --- a/http/auth.go +++ b/http/auth.go @@ -31,6 +31,7 @@ type userInfo struct { HideDotfiles bool `json:"hideDotfiles"` DateFormat bool `json:"dateFormat"` Username string `json:"username"` + AceEditorTheme string `json:"aceEditorTheme"` } type authToken struct { @@ -200,6 +201,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use HideDotfiles: user.HideDotfiles, DateFormat: user.DateFormat, Username: user.Username, + AceEditorTheme: user.AceEditorTheme, }, RegisteredClaims: jwt.RegisteredClaims{ IssuedAt: jwt.NewNumericDate(time.Now()), diff --git a/settings/defaults.go b/settings/defaults.go index d60e36dc..5b6c3f2a 100644 --- a/settings/defaults.go +++ b/settings/defaults.go @@ -8,15 +8,16 @@ import ( // UserDefaults is a type that holds the default values // for some fields on User. type UserDefaults struct { - Scope string `json:"scope"` - Locale string `json:"locale"` - ViewMode users.ViewMode `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Sorting files.Sorting `json:"sorting"` - Perm users.Permissions `json:"perm"` - Commands []string `json:"commands"` - HideDotfiles bool `json:"hideDotfiles"` - DateFormat bool `json:"dateFormat"` + Scope string `json:"scope"` + Locale string `json:"locale"` + ViewMode users.ViewMode `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Sorting files.Sorting `json:"sorting"` + Perm users.Permissions `json:"perm"` + Commands []string `json:"commands"` + HideDotfiles bool `json:"hideDotfiles"` + DateFormat bool `json:"dateFormat"` + AceEditorTheme string `json:"aceEditorTheme"` } // Apply applies the default options to a user. @@ -30,4 +31,5 @@ func (d *UserDefaults) Apply(u *users.User) { u.Commands = d.Commands u.HideDotfiles = d.HideDotfiles u.DateFormat = d.DateFormat + u.AceEditorTheme = d.AceEditorTheme } diff --git a/tools/package.json b/tools/package.json index 9a2bd1c6..9433b94e 100644 --- a/tools/package.json +++ b/tools/package.json @@ -3,5 +3,6 @@ "@commitlint/cli": "^15.0.0", "@commitlint/config-conventional": "^15.0.0", "standard-version": "^9.3.2" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/users/users.go b/users/users.go index e0310f21..020faf11 100644 --- a/users/users.go +++ b/users/users.go @@ -20,21 +20,22 @@ const ( // User describes a user. type User struct { - ID uint `storm:"id,increment" json:"id"` - Username string `storm:"unique" json:"username"` - Password string `json:"password"` - Scope string `json:"scope"` - Locale string `json:"locale"` - LockPassword bool `json:"lockPassword"` - ViewMode ViewMode `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Perm Permissions `json:"perm"` - Commands []string `json:"commands"` - Sorting files.Sorting `json:"sorting"` - Fs afero.Fs `json:"-" yaml:"-"` - Rules []rules.Rule `json:"rules"` - HideDotfiles bool `json:"hideDotfiles"` - DateFormat bool `json:"dateFormat"` + ID uint `storm:"id,increment" json:"id"` + Username string `storm:"unique" json:"username"` + Password string `json:"password"` + Scope string `json:"scope"` + Locale string `json:"locale"` + LockPassword bool `json:"lockPassword"` + ViewMode ViewMode `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Perm Permissions `json:"perm"` + Commands []string `json:"commands"` + Sorting files.Sorting `json:"sorting"` + Fs afero.Fs `json:"-" yaml:"-"` + Rules []rules.Rule `json:"rules"` + HideDotfiles bool `json:"hideDotfiles"` + DateFormat bool `json:"dateFormat"` + AceEditorTheme string `json:"aceEditorTheme"` } // GetRules implements rules.Provider. From 692ca5eaf01e4dcf346ba03f82c5dbd50cce246b Mon Sep 17 00:00:00 2001 From: MSomnium Studios <70982507+ArielLeyva@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:54:28 -0400 Subject: [PATCH 092/266] fix(upload): throttle upload speed calculation to 100ms to avoid Infinity MB/s (#5456) Co-authored-by: Henrique Dias --- .../src/components/prompts/UploadFiles.vue | 29 ++++++++++++-- http/auth.go | 40 +++++++++---------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/frontend/src/components/prompts/UploadFiles.vue b/frontend/src/components/prompts/UploadFiles.vue index 883fffe3..4d96d5bb 100644 --- a/frontend/src/components/prompts/UploadFiles.vue +++ b/frontend/src/components/prompts/UploadFiles.vue @@ -14,7 +14,7 @@ }}
-
{{ speedMbytes }}/s
+
{{ speedText }}/s
{{ formattedETA }} remaining
{{ sentPercent }}% Completed
@@ -88,6 +88,7 @@ const uploadStore = useUploadStore(); const { sentBytes, totalBytes } = storeToRefs(uploadStore); const byteToMbyte = partial({ exponent: 2 }); +const byteToKbyte = partial({ exponent: 1 }); const sentPercent = computed(() => ((uploadStore.sentBytes / uploadStore.totalBytes) * 100).toFixed(2) @@ -95,11 +96,33 @@ const sentPercent = computed(() => const sentMbytes = computed(() => byteToMbyte(uploadStore.sentBytes)); const totalMbytes = computed(() => byteToMbyte(uploadStore.totalBytes)); -const speedMbytes = computed(() => byteToMbyte(speed.value)); +const speedText = computed(() => { + const bytes = speed.value; + + if (bytes < 1024 * 1024) { + const kb = parseFloat(byteToKbyte(bytes)); + return `${kb.toFixed(2)} KB`; + } else { + const mb = parseFloat(byteToMbyte(bytes)); + return `${mb.toFixed(2)} MB`; + } +}); let lastSpeedUpdate: number = 0; let recentSpeeds: number[] = []; +let lastThrottleTime = 0; + +const throttledCalculateSpeed = (sentBytes: number, oldSentBytes: number) => { + const now = Date.now(); + if (now - lastThrottleTime < 100) { + return; + } + + lastThrottleTime = now; + calculateSpeed(sentBytes, oldSentBytes); +}; + const calculateSpeed = (sentBytes: number, oldSentBytes: number) => { // Reset the state when the uploads batch is complete if (sentBytes === 0) { @@ -149,7 +172,7 @@ const calculateEta = () => { eta.value = remainingSize / speedBytesPerSecond; }; -watch(sentBytes, calculateSpeed); +watch(sentBytes, throttledCalculateSpeed); watch(totalBytes, (totalBytes, oldTotalBytes) => { if (oldTotalBytes !== 0) { diff --git a/http/auth.go b/http/auth.go index 62d6779e..18d10025 100644 --- a/http/auth.go +++ b/http/auth.go @@ -21,16 +21,16 @@ const ( ) type userInfo struct { - ID uint `json:"id"` - Locale string `json:"locale"` - ViewMode users.ViewMode `json:"viewMode"` - SingleClick bool `json:"singleClick"` - Perm users.Permissions `json:"perm"` - Commands []string `json:"commands"` - LockPassword bool `json:"lockPassword"` - HideDotfiles bool `json:"hideDotfiles"` - DateFormat bool `json:"dateFormat"` - Username string `json:"username"` + ID uint `json:"id"` + Locale string `json:"locale"` + ViewMode users.ViewMode `json:"viewMode"` + SingleClick bool `json:"singleClick"` + Perm users.Permissions `json:"perm"` + Commands []string `json:"commands"` + LockPassword bool `json:"lockPassword"` + HideDotfiles bool `json:"hideDotfiles"` + DateFormat bool `json:"dateFormat"` + Username string `json:"username"` AceEditorTheme string `json:"aceEditorTheme"` } @@ -191,16 +191,16 @@ func renewHandler(tokenExpireTime time.Duration) handleFunc { func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User, tokenExpirationTime time.Duration) (int, error) { claims := &authToken{ User: userInfo{ - ID: user.ID, - Locale: user.Locale, - ViewMode: user.ViewMode, - SingleClick: user.SingleClick, - Perm: user.Perm, - LockPassword: user.LockPassword, - Commands: user.Commands, - HideDotfiles: user.HideDotfiles, - DateFormat: user.DateFormat, - Username: user.Username, + ID: user.ID, + Locale: user.Locale, + ViewMode: user.ViewMode, + SingleClick: user.SingleClick, + Perm: user.Perm, + LockPassword: user.LockPassword, + Commands: user.Commands, + HideDotfiles: user.HideDotfiles, + DateFormat: user.DateFormat, + Username: user.Username, AceEditorTheme: user.AceEditorTheme, }, RegisteredClaims: jwt.RegisteredClaims{ From d29ad356d1067c87b2821debab91286549f512a0 Mon Sep 17 00:00:00 2001 From: MSomnium Studios <70982507+ArielLeyva@users.noreply.github.com> Date: Thu, 25 Sep 2025 10:57:30 -0400 Subject: [PATCH 093/266] feat: Improved path display in the new file and directory modal (#5451) --- .../src/components/prompts/CreateFilePath.vue | 87 +++++++++++++++++++ frontend/src/components/prompts/NewDir.vue | 2 + frontend/src/components/prompts/NewFile.vue | 2 + 3 files changed, 91 insertions(+) create mode 100644 frontend/src/components/prompts/CreateFilePath.vue diff --git a/frontend/src/components/prompts/CreateFilePath.vue b/frontend/src/components/prompts/CreateFilePath.vue new file mode 100644 index 00000000..9636b6cc --- /dev/null +++ b/frontend/src/components/prompts/CreateFilePath.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/frontend/src/components/prompts/NewDir.vue b/frontend/src/components/prompts/NewDir.vue index 1eb6d481..85d47bb8 100644 --- a/frontend/src/components/prompts/NewDir.vue +++ b/frontend/src/components/prompts/NewDir.vue @@ -14,6 +14,7 @@ v-model.trim="name" tabindex="1" /> +
@@ -48,6 +49,7 @@ import { files as api } from "@/api"; import url from "@/utils/url"; import { useRoute, useRouter } from "vue-router"; import { useI18n } from "vue-i18n"; +import CreateFilePath from "@/components/prompts/CreateFilePath.vue"; const $showError = inject("$showError")!; diff --git a/frontend/src/components/prompts/NewFile.vue b/frontend/src/components/prompts/NewFile.vue index b7c05d44..d3fb34ed 100644 --- a/frontend/src/components/prompts/NewFile.vue +++ b/frontend/src/components/prompts/NewFile.vue @@ -13,6 +13,7 @@ @keyup.enter="submit" v-model.trim="name" /> +
@@ -42,6 +43,7 @@ import { useI18n } from "vue-i18n"; import { useRoute, useRouter } from "vue-router"; import { useFileStore } from "@/stores/file"; import { useLayoutStore } from "@/stores/layout"; +import CreateFilePath from "@/components/prompts/CreateFilePath.vue"; import { files as api } from "@/api"; import url from "@/utils/url"; From c4725428e07da72b855009e2c13c6ed91d32e0b7 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Sep 2025 17:09:16 +0200 Subject: [PATCH 094/266] fix: computation of file path --- frontend/src/components/prompts/CreateFilePath.vue | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/prompts/CreateFilePath.vue b/frontend/src/components/prompts/CreateFilePath.vue index 9636b6cc..ec470f3a 100644 --- a/frontend/src/components/prompts/CreateFilePath.vue +++ b/frontend/src/components/prompts/CreateFilePath.vue @@ -41,12 +41,11 @@ const container = ref(null); const path = computed(() => { let basePath = fileStore.isFiles ? route.path : url.removeLastDir(route.path); + if (!basePath.endsWith("/")) { + basePath += "/"; + } basePath += props.name; - - return basePath - .replace(/^\/[^\/]+/, "") - .split("/") - .filter(Boolean); + return basePath.split("/").filter(Boolean).splice(1); }); watch(path, () => { From 949ddffef20e38169902c5fd74dca4815dcecf11 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Sep 2025 17:13:30 +0200 Subject: [PATCH 095/266] fix: some formatting issues with i18n files --- frontend/src/i18n/ar.json | 4 ++-- frontend/src/i18n/ca.json | 4 ++-- frontend/src/i18n/cs.json | 4 ++-- frontend/src/i18n/de.json | 4 ++-- frontend/src/i18n/el.json | 4 ++-- frontend/src/i18n/en.json | 4 ++-- frontend/src/i18n/es.json | 4 ++-- frontend/src/i18n/fa.json | 4 ++-- frontend/src/i18n/fr.json | 4 ++-- frontend/src/i18n/he.json | 4 ++-- frontend/src/i18n/hu.json | 4 ++-- frontend/src/i18n/is.json | 4 ++-- frontend/src/i18n/it.json | 4 ++-- frontend/src/i18n/ja.json | 4 ++-- frontend/src/i18n/ko.json | 4 ++-- frontend/src/i18n/nl-be.json | 4 ++-- frontend/src/i18n/no.json | 4 ++-- frontend/src/i18n/pl.json | 4 ++-- frontend/src/i18n/pt-br.json | 4 ++-- frontend/src/i18n/pt.json | 4 ++-- frontend/src/i18n/ro.json | 4 ++-- frontend/src/i18n/ru.json | 4 ++-- frontend/src/i18n/sk.json | 4 ++-- frontend/src/i18n/sv-se.json | 4 ++-- frontend/src/i18n/tr.json | 4 ++-- frontend/src/i18n/uk.json | 4 ++-- frontend/src/i18n/vi.json | 4 ++-- frontend/src/i18n/zh-cn.json | 4 ++-- frontend/src/i18n/zh-tw.json | 4 ++-- 29 files changed, 58 insertions(+), 58 deletions(-) diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 70feef51..9b06d2d3 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -42,8 +42,8 @@ "update": "تحديث", "upload": "رفع", "openFile": "فتح الملف", - "discardChanges": "إلغاء التغييرات", - "saveChanges": "Save changes" + "discardChanges": "إلغاء التغييرات", + "saveChanges": "Save changes" }, "download": { "downloadFile": "تحميل الملف", diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json index 4d698fa5..353eeb22 100644 --- a/frontend/src/i18n/ca.json +++ b/frontend/src/i18n/ca.json @@ -42,8 +42,8 @@ "update": "Actualitzar", "upload": "Pujar", "openFile": "Obrir fitxer", - "discardChanges": "Descartar", - "saveChanges": "Save changes" + "discardChanges": "Descartar", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarregar fitxer", diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json index c7e32842..635a1d96 100644 --- a/frontend/src/i18n/cs.json +++ b/frontend/src/i18n/cs.json @@ -42,8 +42,8 @@ "update": "Aktualizovat", "upload": "Nahrát", "openFile": "Otevřít soubor", - "discardChanges": "Zrušit změny", - "saveChanges": "Save changes" + "discardChanges": "Zrušit změny", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Stáhnout soubor", diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index d22a3be1..40971820 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -42,8 +42,8 @@ "update": "Update", "upload": "Upload", "openFile": "Datei öffnen", - "discardChanges": "Verwerfen", - "saveChanges": "Save changes" + "discardChanges": "Verwerfen", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Download Datei", diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json index 9fed72f1..ba75606f 100644 --- a/frontend/src/i18n/el.json +++ b/frontend/src/i18n/el.json @@ -42,8 +42,8 @@ "update": "Ενημέρωση", "upload": "Μεταφόρτωση", "openFile": "Άνοιγμα αρχείου", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Λήψη αρχείου", diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index b6325511..15a297df 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -42,8 +42,8 @@ "update": "Update", "upload": "Upload", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Download File", diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index e7f9e882..a3565f4f 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -42,8 +42,8 @@ "update": "Actualizar", "upload": "Subir", "openFile": "Abrir archivo", - "discardChanges": "Discard", - "saveChanges": "Guardar cambios" + "discardChanges": "Discard", + "saveChanges": "Guardar cambios" }, "download": { "downloadFile": "Descargar fichero", diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json index 70e10c12..e4a2532e 100644 --- a/frontend/src/i18n/fa.json +++ b/frontend/src/i18n/fa.json @@ -42,8 +42,8 @@ "update": "به روز سانی", "upload": "آپلود", "openFile": "باز کردن فایل", - "discardChanges": "لغو کردن", - "saveChanges": "Save changes" + "discardChanges": "لغو کردن", + "saveChanges": "Save changes" }, "download": { "downloadFile": "دانلود فایل", diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index 16508807..fcbd239b 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -42,8 +42,8 @@ "update": "Mettre à jour", "upload": "Importer", "openFile": "Ouvrir le fichier", - "discardChanges": "Annuler", - "saveChanges": "Save changes" + "discardChanges": "Annuler", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Télécharger le fichier", diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json index a8e89a93..9bb3145a 100644 --- a/frontend/src/i18n/he.json +++ b/frontend/src/i18n/he.json @@ -42,8 +42,8 @@ "update": "עדכון", "upload": "העלאה", "openFile": "פתח קובץ", - "discardChanges": "זריקת השינויים", - "saveChanges": "Save changes" + "discardChanges": "זריקת השינויים", + "saveChanges": "Save changes" }, "download": { "downloadFile": "הורד קובץ", diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json index 00fc419e..0971d9cc 100644 --- a/frontend/src/i18n/hu.json +++ b/frontend/src/i18n/hu.json @@ -42,8 +42,8 @@ "update": "Frissítés", "upload": "Feltöltés", "openFile": "Fájl megnyitása", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Fájl letöltése", diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index c55455e5..65a5eb00 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -42,8 +42,8 @@ "update": "Vista", "upload": "Hlaða upp", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Sækja skjal", diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index 995ba7cd..b1135aac 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -42,8 +42,8 @@ "update": "Aggiorna", "upload": "Carica", "openFile": "Apri file", - "discardChanges": "Ignora", - "saveChanges": "Save changes" + "discardChanges": "Ignora", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Scarica file", diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index 99e4b017..574bf59a 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -42,8 +42,8 @@ "update": "更新", "upload": "アップロード", "openFile": "ファイルを開く", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "ファイルのダウンロード", diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index ec64bd62..ea5a1e67 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -42,8 +42,8 @@ "update": "업데이트", "upload": "업로드", "openFile": "파일 열기", - "discardChanges": "변경 사항 취소", - "saveChanges": "변경사항 저장" + "discardChanges": "변경 사항 취소", + "saveChanges": "변경사항 저장" }, "download": { "downloadFile": "파일 다운로드", diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index c104ef81..af659e5c 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -42,8 +42,8 @@ "update": "Updaten", "upload": "Uploaden", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Bestand downloaden", diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index a3803ae9..08c6992c 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -42,8 +42,8 @@ "update": "Opptater", "upload": "Last opp", "openFile": "Open file", - "discardChanges": "Slett", - "saveChanges": "Lagre Endringane " + "discardChanges": "Slett", + "saveChanges": "Lagre Endringane " }, "download": { "downloadFile": "Nedlast filen", diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 54dd9aed..06f1c8fd 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -42,8 +42,8 @@ "update": "Aktualizuj", "upload": "Wyślij", "openFile": "Otwórz plik", - "discardChanges": "Odrzuć", - "saveChanges": "Zapisz zmiany" + "discardChanges": "Odrzuć", + "saveChanges": "Zapisz zmiany" }, "download": { "downloadFile": "Pobierz plik", diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index 8e314c77..a4938c49 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -42,8 +42,8 @@ "update": "Atualizar", "upload": "Enviar", "openFile": "Abrir", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Baixar arquivo", diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index 4c719cc9..2555eafb 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -42,8 +42,8 @@ "update": "Atualizar", "upload": "Enviar", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarregar ficheiro", diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index 232b0e4d..5f4a630e 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -42,8 +42,8 @@ "update": "Actualizează", "upload": "Încarcă", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Descarcă fișier", diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index 931cf68d..d9407647 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -42,8 +42,8 @@ "update": "Обновить", "upload": "Загрузить", "openFile": "Открыть файл", - "discardChanges": "Отказаться", - "saveChanges": "Save changes" + "discardChanges": "Отказаться", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Скачать файл", diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json index 2f01ef8c..06c73a98 100644 --- a/frontend/src/i18n/sk.json +++ b/frontend/src/i18n/sk.json @@ -42,8 +42,8 @@ "update": "Aktualizovať", "upload": "Nahrať", "openFile": "Otvoriť súbor", - "discardChanges": "Zahodiť", - "saveChanges": "Save changes" + "discardChanges": "Zahodiť", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Stiahnuť súbor", diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index 319b7eb2..47c041c0 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -42,8 +42,8 @@ "update": "Uppdatera", "upload": "Ladda upp", "openFile": "Open file", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Ladda ner fil", diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json index aa0d3558..ed635501 100644 --- a/frontend/src/i18n/tr.json +++ b/frontend/src/i18n/tr.json @@ -42,8 +42,8 @@ "update": "Güncelle", "upload": "Yükle", "openFile": "Dosyayı aç", - "discardChanges": "Discard", - "saveChanges": "Save changes" + "discardChanges": "Discard", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Dosyayı indir", diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index d3f01c9f..a81010f6 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -42,8 +42,8 @@ "update": "Оновити", "upload": "Вивантажити", "openFile": "Відкрити файл", - "discardChanges": "Скасувати", - "saveChanges": "Save changes" + "discardChanges": "Скасувати", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Завантажити файл", diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json index 380f98ff..07864ce8 100644 --- a/frontend/src/i18n/vi.json +++ b/frontend/src/i18n/vi.json @@ -42,8 +42,8 @@ "update": "Cập nhật", "upload": "Tải lên", "openFile": "Mở tệp", - "discardChanges": "Hủy bỏ thay đổi", - "saveChanges": "Save changes" + "discardChanges": "Hủy bỏ thay đổi", + "saveChanges": "Save changes" }, "download": { "downloadFile": "Tải xuống tệp tin", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index c18c7e98..6a8b9065 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -42,8 +42,8 @@ "update": "更新", "upload": "上传", "openFile": "打开文件", - "discardChanges": "放弃更改", - "saveChanges": "Save changes" + "discardChanges": "放弃更改", + "saveChanges": "Save changes" }, "download": { "downloadFile": "下载文件", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index adcfde91..4ceb886c 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -42,8 +42,8 @@ "update": "更新", "upload": "上傳", "openFile": "開啟檔案", - "discardChanges": "放棄變更", - "saveChanges": "Save changes" + "discardChanges": "放棄變更", + "saveChanges": "Save changes" }, "download": { "downloadFile": "下載檔案", From 1165f00bd4dcb0dcfbc084f54f51902ba4b4a714 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Thu, 25 Sep 2025 17:19:21 +0200 Subject: [PATCH 096/266] feat: Updates for project File Browser (#5457) Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- frontend/src/i18n/ar.json | 1 + frontend/src/i18n/ca.json | 1 + frontend/src/i18n/cs.json | 1 + frontend/src/i18n/de.json | 1 + frontend/src/i18n/el.json | 1 + frontend/src/i18n/es.json | 1 + frontend/src/i18n/fa.json | 1 + frontend/src/i18n/fr.json | 1 + frontend/src/i18n/he.json | 1 + frontend/src/i18n/hu.json | 1 + frontend/src/i18n/is.json | 1 + frontend/src/i18n/it.json | 1 + frontend/src/i18n/ja.json | 1 + frontend/src/i18n/ko.json | 1 + frontend/src/i18n/nl-be.json | 1 + frontend/src/i18n/no.json | 1 + frontend/src/i18n/pl.json | 1 + frontend/src/i18n/pt-br.json | 1 + frontend/src/i18n/pt.json | 1 + frontend/src/i18n/ro.json | 1 + frontend/src/i18n/ru.json | 1 + frontend/src/i18n/sk.json | 1 + frontend/src/i18n/sv-se.json | 1 + frontend/src/i18n/tr.json | 1 + frontend/src/i18n/uk.json | 1 + frontend/src/i18n/vi.json | 1 + frontend/src/i18n/zh-cn.json | 1 + frontend/src/i18n/zh-tw.json | 1 + 28 files changed, 28 insertions(+) diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json index 9b06d2d3..26e95765 100644 --- a/frontend/src/i18n/ar.json +++ b/frontend/src/i18n/ar.json @@ -158,6 +158,7 @@ "video": "فيديوهات" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "إدارة", "administrator": "مدير", "allowCommands": "تنفيذ اﻷوامر", diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json index 353eeb22..e17c7c80 100644 --- a/frontend/src/i18n/ca.json +++ b/frontend/src/i18n/ca.json @@ -158,6 +158,7 @@ "video": "Vídeo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Executar comandes", diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json index 635a1d96..914b843f 100644 --- a/frontend/src/i18n/cs.json +++ b/frontend/src/i18n/cs.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrátor", "allowCommands": "Povolit příkazy", diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json index 40971820..48c91eb8 100644 --- a/frontend/src/i18n/de.json +++ b/frontend/src/i18n/de.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Befehle ausführen", diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json index ba75606f..97206a1f 100644 --- a/frontend/src/i18n/el.json +++ b/frontend/src/i18n/el.json @@ -158,6 +158,7 @@ "video": "Βίντεο" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Διαχειριστής", "administrator": "Διαχειριστής", "allowCommands": "Εκτέλεση εντολών", diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json index a3565f4f..2981ece1 100644 --- a/frontend/src/i18n/es.json +++ b/frontend/src/i18n/es.json @@ -158,6 +158,7 @@ "video": "Vídeo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Ejecutar comandos", diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json index e4a2532e..1d885fcc 100644 --- a/frontend/src/i18n/fa.json +++ b/frontend/src/i18n/fa.json @@ -158,6 +158,7 @@ "video": "ویدئو " }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "اجرای دستورات", diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json index fcbd239b..bf07499a 100644 --- a/frontend/src/i18n/fr.json +++ b/frontend/src/i18n/fr.json @@ -158,6 +158,7 @@ "video": "Vidéo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrateur·ice", "allowCommands": "Exécuter des commandes", diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json index 9bb3145a..6576ebd0 100644 --- a/frontend/src/i18n/he.json +++ b/frontend/src/i18n/he.json @@ -158,6 +158,7 @@ "video": "וידאו" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "מנהל", "administrator": "מנהל ראשי", "allowCommands": "הפעלת פקודות", diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json index 0971d9cc..dd58ed1d 100644 --- a/frontend/src/i18n/hu.json +++ b/frontend/src/i18n/hu.json @@ -158,6 +158,7 @@ "video": "Videó" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Adminisztrátor", "allowCommands": "Parancsok futtatása", diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json index 65a5eb00..431f21ef 100644 --- a/frontend/src/i18n/is.json +++ b/frontend/src/i18n/is.json @@ -158,6 +158,7 @@ "video": "Myndbönd" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Stjórnandi", "administrator": "Stjórnandi", "allowCommands": "Senda skipanir", diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json index b1135aac..929d90ed 100644 --- a/frontend/src/i18n/it.json +++ b/frontend/src/i18n/it.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Amministratore", "allowCommands": "Esegui comandi", diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json index 574bf59a..0e6b9c04 100644 --- a/frontend/src/i18n/ja.json +++ b/frontend/src/i18n/ja.json @@ -158,6 +158,7 @@ "video": "動画" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "管理者", "administrator": "管理者", "allowCommands": "コマンドの実行", diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json index ea5a1e67..64a6c7d5 100644 --- a/frontend/src/i18n/ko.json +++ b/frontend/src/i18n/ko.json @@ -158,6 +158,7 @@ "video": "비디오" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "관리자", "administrator": "관리자", "allowCommands": "명령 실행", diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json index af659e5c..78a7c281 100644 --- a/frontend/src/i18n/nl-be.json +++ b/frontend/src/i18n/nl-be.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Commando's uitvoeren", diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json index 08c6992c..3eea3638 100644 --- a/frontend/src/i18n/no.json +++ b/frontend/src/i18n/no.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Utfør kommandoer", diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json index 06f1c8fd..b9db7455 100644 --- a/frontend/src/i18n/pl.json +++ b/frontend/src/i18n/pl.json @@ -158,6 +158,7 @@ "video": "Wideo" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Wykonaj polecenie", diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json index a4938c49..d29f98d6 100644 --- a/frontend/src/i18n/pt-br.json +++ b/frontend/src/i18n/pt-br.json @@ -158,6 +158,7 @@ "video": "Vídeos" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Executar comandos", diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json index 2555eafb..e54a4f0d 100644 --- a/frontend/src/i18n/pt.json +++ b/frontend/src/i18n/pt.json @@ -158,6 +158,7 @@ "video": "Vídeos" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrador", "allowCommands": "Executar comandos", diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json index 5f4a630e..73719a4e 100644 --- a/frontend/src/i18n/ro.json +++ b/frontend/src/i18n/ro.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrator", "allowCommands": "Execută comenzi", diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json index d9407647..0678ce14 100644 --- a/frontend/src/i18n/ru.json +++ b/frontend/src/i18n/ru.json @@ -158,6 +158,7 @@ "video": "Видео" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Админ", "administrator": "Администратор", "allowCommands": "Запуск команд", diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json index 06c73a98..68112fba 100644 --- a/frontend/src/i18n/sk.json +++ b/frontend/src/i18n/sk.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administrátor", "allowCommands": "Vykonávať príkazy", diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json index 47c041c0..9f66a141 100644 --- a/frontend/src/i18n/sv-se.json +++ b/frontend/src/i18n/sv-se.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Admin", "administrator": "Administratör", "allowCommands": "Exekvera kommandon", diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json index ed635501..7493821e 100644 --- a/frontend/src/i18n/tr.json +++ b/frontend/src/i18n/tr.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Yönetim", "administrator": "Yönetici", "allowCommands": "Komutları çalıştır", diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json index a81010f6..40a96893 100644 --- a/frontend/src/i18n/uk.json +++ b/frontend/src/i18n/uk.json @@ -158,6 +158,7 @@ "video": "Відео" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Адмін", "administrator": "Адміністратор", "allowCommands": "Запуск команд", diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json index 07864ce8..fab93759 100644 --- a/frontend/src/i18n/vi.json +++ b/frontend/src/i18n/vi.json @@ -158,6 +158,7 @@ "video": "Video" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "Quản trị viên", "administrator": "Người quản trị", "allowCommands": "Thực thi lệnh", diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json index 6a8b9065..15cf8e3c 100644 --- a/frontend/src/i18n/zh-cn.json +++ b/frontend/src/i18n/zh-cn.json @@ -158,6 +158,7 @@ "video": "视频" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "管理员", "administrator": "管理员", "allowCommands": "执行命令(Shell 命令)", diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json index 4ceb886c..d59f1efd 100644 --- a/frontend/src/i18n/zh-tw.json +++ b/frontend/src/i18n/zh-tw.json @@ -158,6 +158,7 @@ "video": "影片" }, "settings": { + "aceEditorTheme": "Ace editor theme", "admin": "管理員", "administrator": "管理員", "allowCommands": "執行命令", From 878cdfbc52bdb4c4385f24904a87927f852cb907 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 25 Sep 2025 17:20:12 +0200 Subject: [PATCH 097/266] chore(release): 2.44.0 --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f81c8cd4..9bf8bd77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,26 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.44.0](https://github.com/filebrowser/filebrowser/compare/v2.43.0...v2.44.0) (2025-09-25) + + +### Features + +* allow setting ace editor theme ([#3826](https://github.com/filebrowser/filebrowser/issues/3826)) ([b9787c7](https://github.com/filebrowser/filebrowser/commit/b9787c78f3889171f94db19e7655dce68c64b6fb)) +* Improved path display in the new file and directory modal ([#5451](https://github.com/filebrowser/filebrowser/issues/5451)) ([d29ad35](https://github.com/filebrowser/filebrowser/commit/d29ad356d1067c87b2821debab91286549f512a0)) +* Translate frontend/src/i18n/en.json in no ([dec7a02](https://github.com/filebrowser/filebrowser/commit/dec7a027378fbc6948d203199c44a640a141bcad)) +* Updates for project File Browser ([#5446](https://github.com/filebrowser/filebrowser/issues/5446)) ([4ff247e](https://github.com/filebrowser/filebrowser/commit/4ff247e134e4d61668ee656a258ed67f71414e18)) +* Updates for project File Browser ([#5450](https://github.com/filebrowser/filebrowser/issues/5450)) ([0eade71](https://github.com/filebrowser/filebrowser/commit/0eade717ce9d04bf48051922f11d983edbc7c2d0)) +* Updates for project File Browser ([#5457](https://github.com/filebrowser/filebrowser/issues/5457)) ([1165f00](https://github.com/filebrowser/filebrowser/commit/1165f00bd4dcb0dcfbc084f54f51902ba4b4a714)) + + +### Bug Fixes + +* computation of file path ([c472542](https://github.com/filebrowser/filebrowser/commit/c4725428e07da72b855009e2c13c6ed91d32e0b7)) +* show login when session token expires ([e6c674b](https://github.com/filebrowser/filebrowser/commit/e6c674b3c616831942c4d4aacab0907d58003e23)) +* some formatting issues with i18n files ([949ddff](https://github.com/filebrowser/filebrowser/commit/949ddffef20e38169902c5fd74dca4815dcecf11)) +* **upload:** throttle upload speed calculation to 100ms to avoid Infinity MB/s ([#5456](https://github.com/filebrowser/filebrowser/issues/5456)) ([692ca5e](https://github.com/filebrowser/filebrowser/commit/692ca5eaf01e4dcf346ba03f82c5dbd50cce246b)) + ## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13) From d0039afbb76a9364c1e6ac9715ccc3c239dc8cb6 Mon Sep 17 00:00:00 2001 From: Ryan <43447928+Rmiller5466@users.noreply.github.com> Date: Fri, 3 Oct 2025 04:42:24 -0400 Subject: [PATCH 098/266] fix: wrong url on settings branding link --- frontend/src/views/settings/Global.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/settings/Global.vue b/frontend/src/views/settings/Global.vue index e397c6f7..0a42a293 100644 --- a/frontend/src/views/settings/Global.vue +++ b/frontend/src/views/settings/Global.vue @@ -65,7 +65,7 @@ {{ t("settings.documentation") }} From a397e7305d1572baf67823413f97a29eea38f0cc Mon Sep 17 00:00:00 2001 From: Ryan <43447928+Rmiller5466@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:45:36 -0400 Subject: [PATCH 099/266] fix: editor discard prompt doesn't save nor discard Co-authored-by: Ryan Miller --- .../components/prompts/DiscardEditorChanges.vue | 10 ++-------- frontend/src/views/files/Editor.vue | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/prompts/DiscardEditorChanges.vue b/frontend/src/components/prompts/DiscardEditorChanges.vue index bd6bc49a..7a99c5fc 100644 --- a/frontend/src/components/prompts/DiscardEditorChanges.vue +++ b/frontend/src/components/prompts/DiscardEditorChanges.vue @@ -17,7 +17,7 @@