signup,
+ hideLoginButton: () => hideLoginButton,
version: () => version,
disableExternal: () => disableExternal,
disableUsedPercentage: () => disableUsedPercentage,
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 15a297df..9272cff4 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -166,6 +166,7 @@
"allowNew": "Create new files and directories",
"allowPublish": "Publish new posts and pages",
"allowSignup": "Allow users to signup",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(leave blank to avoid changes)",
"branding": "Branding",
"brandingDirectoryPath": "Branding directory path",
diff --git a/frontend/src/types/settings.d.ts b/frontend/src/types/settings.d.ts
index ba56c612..562c718b 100644
--- a/frontend/src/types/settings.d.ts
+++ b/frontend/src/types/settings.d.ts
@@ -1,6 +1,7 @@
interface ISettings {
signup: boolean;
createUserDir: boolean;
+ hideLoginButton: boolean;
minimumPasswordLength: number;
userHomeBasePath: string;
defaults: SettingsDefaults;
diff --git a/frontend/src/utils/constants.ts b/frontend/src/utils/constants.ts
index 3f131b1a..ae491397 100644
--- a/frontend/src/utils/constants.ts
+++ b/frontend/src/utils/constants.ts
@@ -18,6 +18,7 @@ const enableExec: boolean = window.FileBrowser.EnableExec;
const tusSettings = window.FileBrowser.TusSettings;
const origin = window.location.origin;
const tusEndpoint = `/api/tus`;
+const hideLoginButton = window.FileBrowser.HideLoginButton;
export {
name,
@@ -39,4 +40,5 @@ export {
tusSettings,
origin,
tusEndpoint,
+ hideLoginButton,
};
diff --git a/frontend/src/views/settings/Global.vue b/frontend/src/views/settings/Global.vue
index 0a42a293..3d391206 100644
--- a/frontend/src/views/settings/Global.vue
+++ b/frontend/src/views/settings/Global.vue
@@ -18,6 +18,11 @@
{{ t("settings.createUserDir") }}
+
+
+ {{ t("settings.hideLoginButton") }}
+
+
Date: Fri, 14 Nov 2025 10:53:16 -0500
Subject: [PATCH 007/120] feat: add context menu (#3343)
Co-authored-by: Henrique Dias
---
frontend/src/components/ContextMenu.vue | 47 +++++++++++
frontend/src/components/files/ListingItem.vue | 12 +++
frontend/src/components/prompts/Move.vue | 1 +
frontend/src/css/context-menu.css | 21 +++++
frontend/src/css/styles.css | 3 +-
frontend/src/views/files/FileListing.vue | 83 +++++++++++++++++--
6 files changed, 160 insertions(+), 7 deletions(-)
create mode 100644 frontend/src/components/ContextMenu.vue
create mode 100644 frontend/src/css/context-menu.css
diff --git a/frontend/src/components/ContextMenu.vue b/frontend/src/components/ContextMenu.vue
new file mode 100644
index 00000000..14663fd9
--- /dev/null
+++ b/frontend/src/components/ContextMenu.vue
@@ -0,0 +1,47 @@
+
+
+
+
+
diff --git a/frontend/src/components/files/ListingItem.vue b/frontend/src/components/files/ListingItem.vue
index 14d897cf..5db88aba 100644
--- a/frontend/src/components/files/ListingItem.vue
+++ b/frontend/src/components/files/ListingItem.vue
@@ -20,6 +20,7 @@
:aria-label="name"
:aria-selected="isSelected"
:data-ext="getExtension(name).toLowerCase()"
+ @contextmenu="contextMenu"
>
![]()
{
else click(event);
};
+const contextMenu = (event: MouseEvent) => {
+ event.preventDefault();
+ if (
+ fileStore.selected.length === 0 ||
+ event.ctrlKey ||
+ fileStore.selected.indexOf(props.index) === -1
+ ) {
+ click(event);
+ }
+};
+
const click = (event: Event | KeyboardEvent) => {
if (!singleClick.value && fileStore.selectedCount !== 0)
event.preventDefault();
diff --git a/frontend/src/components/prompts/Move.vue b/frontend/src/components/prompts/Move.vue
index d30aca7b..d92e4b6e 100644
--- a/frontend/src/components/prompts/Move.vue
+++ b/frontend/src/components/prompts/Move.vue
@@ -5,6 +5,7 @@
+
{{ $t("prompts.moveMessage") }}
(dest = val)"
diff --git a/frontend/src/css/context-menu.css b/frontend/src/css/context-menu.css
new file mode 100644
index 00000000..d0741d16
--- /dev/null
+++ b/frontend/src/css/context-menu.css
@@ -0,0 +1,21 @@
+.context-menu {
+ position: absolute;
+ background: var(--surfacePrimary);
+ min-width: 180px;
+ max-width: 220px;
+ border: 1px solid var(--borderSecondary);
+ box-shadow: 0 2px 4px var(--borderPrimary);
+ z-index: 999;
+}
+
+.context-menu .action {
+ display: block;
+ width: 100%;
+ border-radius: 0;
+ display: flex;
+ align-items: center;
+}
+
+.context-menu .action .counter {
+ left: 1.75em;
+}
diff --git a/frontend/src/css/styles.css b/frontend/src/css/styles.css
index a793b025..89261166 100644
--- a/frontend/src/css/styles.css
+++ b/frontend/src/css/styles.css
@@ -17,6 +17,7 @@
@import "./mobile.css";
@import "./epubReader.css";
@import "./mdPreview.css";
+@import "./context-menu.css";
/* For testing only
:focus {
@@ -459,4 +460,4 @@ html[dir="rtl"] .card-content .small + input {
html[dir="rtl"] .card.floating .card-content .file-list {
direction: ltr;
text-align: left;
-}
+}
\ No newline at end of file
diff --git a/frontend/src/views/files/FileListing.vue b/frontend/src/views/files/FileListing.vue
index 3f052d54..e981b76b 100644
--- a/frontend/src/views/files/FileListing.vue
+++ b/frontend/src/views/files/FileListing.vue
@@ -207,7 +207,10 @@
{{ t("files.folders") }}
-
+
-
-
{{ t("files.files") }}
-
+
+ {{ t("files.files") }}
+
+
-
+
+
+
+
+
+
+
+
+
(280);
const dragCounter = ref
(0);
const width = ref(window.innerWidth);
const itemWeight = ref(0);
+const isContextMenuVisible = ref(false);
+const contextMenuPos = ref<{ x: number; y: number }>({ x: 0, y: 0 });
const $showError = inject("$showError")!;
@@ -438,7 +496,7 @@ watch(req, () => {
onMounted(() => {
// Check the columns size for the first time.
- colunmsResize();
+ columnsResize();
// How much every listing item affects the window height
setItemWeight();
@@ -642,7 +700,7 @@ const paste = (event: Event) => {
action(overwrite, rename);
};
-const colunmsResize = () => {
+const columnsResize = () => {
// Update the columns size based on the window width.
const items_ = css(["#listing.mosaic .item", ".mosaic#listing .item"]);
if (items_ === null) return;
@@ -850,7 +908,7 @@ const toggleMultipleSelection = () => {
};
const windowsResize = throttle(() => {
- colunmsResize();
+ columnsResize();
width.value = window.innerWidth;
// Listing element is not displayed
@@ -977,4 +1035,17 @@ const revealPreviousItem = () => {
return true;
};
+
+const showContextMenu = (event: MouseEvent) => {
+ event.preventDefault();
+ isContextMenuVisible.value = true;
+ contextMenuPos.value = {
+ x: event.clientX + 8,
+ y: event.clientY + Math.floor(window.scrollY),
+ };
+};
+
+const hideContextMenu = () => {
+ isContextMenuVisible.value = false;
+};
From fb5d099f8514516216f407be012d2e3f25de2441 Mon Sep 17 00:00:00 2001
From: "transifex-integration[bot]"
<43880903+transifex-integration[bot]@users.noreply.github.com>
Date: Fri, 14 Nov 2025 17:47:21 +0100
Subject: [PATCH 008/120] feat: Updates for project File Browser (#5544)
---
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/hr.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 +
29 files changed, 29 insertions(+)
diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json
index 26e95765..ebf6a92b 100644
--- a/frontend/src/i18n/ar.json
+++ b/frontend/src/i18n/ar.json
@@ -166,6 +166,7 @@
"allowNew": "إنشاء ملفات و مجلدات جديدة",
"allowPublish": "نشر مقالات و صفحات جديدة",
"allowSignup": "اسمح للمستخدمين بالاشتراك",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(أتركه فارغاً إن لم ترد تغييره)",
"branding": "الشعار",
"brandingDirectoryPath": "مسار مجلد الشعار",
diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json
index e17c7c80..e895ca78 100644
--- a/frontend/src/i18n/ca.json
+++ b/frontend/src/i18n/ca.json
@@ -166,6 +166,7 @@
"allowNew": "Crear nous fitxers i carpetes",
"allowPublish": "Publicar nous posts i pàgines",
"allowSignup": "Permetre registre d'usuaris",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(deixar en blanc per evitar canvis)",
"branding": "Marca",
"brandingDirectoryPath": "Ruta de la carpeta de personalització de marca",
diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json
index 914b843f..2d84ced7 100644
--- a/frontend/src/i18n/cs.json
+++ b/frontend/src/i18n/cs.json
@@ -166,6 +166,7 @@
"allowNew": "Vytvářet nové soubory a adresáře",
"allowPublish": "Publikovat nové příspěvky a stránky",
"allowSignup": "Povolit uživatelům registraci",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(ponechte prázdné pro zabránění změnám)",
"branding": "Branding",
"brandingDirectoryPath": "Cesta ke složce s brandingem",
diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json
index 48c91eb8..52cd2fc3 100644
--- a/frontend/src/i18n/de.json
+++ b/frontend/src/i18n/de.json
@@ -166,6 +166,7 @@
"allowNew": "Erstellen neuer Dateien und Ordner",
"allowPublish": "Veröffentlichen von neuen Beiträgen und Seiten",
"allowSignup": "Erlaube Benutzern sich zu registrieren",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(leer lassen, um Änderungen zu vermeiden)",
"branding": "Design",
"brandingDirectoryPath": "Designverzeichnispfad",
diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json
index 97206a1f..0d98e90a 100644
--- a/frontend/src/i18n/el.json
+++ b/frontend/src/i18n/el.json
@@ -166,6 +166,7 @@
"allowNew": "Δημιουργία νέων αρχείων και φακέλων",
"allowPublish": "Δημοσίευση νέων αναρτήσεων και σελίδων",
"allowSignup": "Να επιτρέπεται η εγγραφή νέων χρηστών",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(αφήστε το κενό για αποφυγή αλλαγών)",
"branding": "Εξατομίκευση",
"brandingDirectoryPath": "Διαδρομή φακέλου εξατομίκευσης",
diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json
index 2981ece1..9d0b0b99 100644
--- a/frontend/src/i18n/es.json
+++ b/frontend/src/i18n/es.json
@@ -166,6 +166,7 @@
"allowNew": "Crear nuevos archivos y carpetas",
"allowPublish": "Publicar nuevos posts y páginas",
"allowSignup": "Permitir registro de usuarios",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(dejar en blanco para evitar cambios)",
"branding": "Marca",
"brandingDirectoryPath": "Ruta de la carpeta de personalizacion de marca",
diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json
index 1d885fcc..f3b5bc17 100644
--- a/frontend/src/i18n/fa.json
+++ b/frontend/src/i18n/fa.json
@@ -166,6 +166,7 @@
"allowNew": "ایجاد فایلها و پوشه های جدید",
"allowPublish": "انتشار پست ها و صفحات جدید",
"allowSignup": "اجاره دادن به کاربران برای ثبت نام",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(خالی بگذارید تا تغییر ایجاد نشود)",
"branding": "برندسازی",
"brandingDirectoryPath": "مسیر پوشه برند",
diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json
index bf07499a..421d4cc4 100644
--- a/frontend/src/i18n/fr.json
+++ b/frontend/src/i18n/fr.json
@@ -166,6 +166,7 @@
"allowNew": "Créer de nouveaux fichiers et dossiers",
"allowPublish": "Publier de nouveaux posts et pages",
"allowSignup": "Autoriser les utilisateur·ices à s'inscrire",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(Laisser vide pour conserver l'actuel)",
"branding": "Image de marque",
"brandingDirectoryPath": "Chemin du dossier d'image de marque",
diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json
index 6576ebd0..d932b0ae 100644
--- a/frontend/src/i18n/he.json
+++ b/frontend/src/i18n/he.json
@@ -166,6 +166,7 @@
"allowNew": "יצירת קבצים ותיקיות חדשות",
"allowPublish": "פרסום פוסטים ודפים חדשים",
"allowSignup": "אפשר למשתמשים חדשים להירשם",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(השאר ריק כדי למנוע שינויים)",
"branding": "מיתוג",
"brandingDirectoryPath": "נתיב תיקיית מיתוג",
diff --git a/frontend/src/i18n/hr.json b/frontend/src/i18n/hr.json
index 433a3b43..5c241daf 100644
--- a/frontend/src/i18n/hr.json
+++ b/frontend/src/i18n/hr.json
@@ -166,6 +166,7 @@
"allowNew": "Stvori nove datoteke i mape",
"allowPublish": "Objavi nove objave i stranice",
"allowSignup": "Dopusti registraciju korisnicima",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(ostavite prazno kako biste izbjegli promjene)",
"branding": "Brendiranje",
"brandingDirectoryPath": "Put brendiranja",
diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json
index dd58ed1d..79396c72 100644
--- a/frontend/src/i18n/hu.json
+++ b/frontend/src/i18n/hu.json
@@ -166,6 +166,7 @@
"allowNew": "Új fájlok és mappák létrehozása",
"allowPublish": "Új bejegyzések és oldalak létrehozása",
"allowSignup": "Felhasználók regisztrációjának engedélyezése",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(üresen hagyva nincs változás)",
"branding": "Márkázás",
"brandingDirectoryPath": "Márkázás mappaútvonala",
diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json
index 431f21ef..e67a4bab 100644
--- a/frontend/src/i18n/is.json
+++ b/frontend/src/i18n/is.json
@@ -166,6 +166,7 @@
"allowNew": "Búa til ný skjöl og möppur",
"allowPublish": "Gefa út nýjar færslur og síður",
"allowSignup": "Leyfa nýjum notendum að skrá sig",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(engar breytingar ef ekkert er skrifað)",
"branding": "Útlit",
"brandingDirectoryPath": "Mappa fyrir branding-skjöl",
diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json
index 929d90ed..7e04c40f 100644
--- a/frontend/src/i18n/it.json
+++ b/frontend/src/i18n/it.json
@@ -166,6 +166,7 @@
"allowNew": "Crea nuovi files o cartelle",
"allowPublish": "Pubblica nuovi post e pagine",
"allowSignup": "Permetti agli utenti di registrarsi",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(lascia vuoto per evitare cambiamenti)",
"branding": "Branding",
"brandingDirectoryPath": "Directory del branding",
diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json
index 0e6b9c04..bda66d09 100644
--- a/frontend/src/i18n/ja.json
+++ b/frontend/src/i18n/ja.json
@@ -166,6 +166,7 @@
"allowNew": "ファイルやフォルダーの新規作成",
"allowPublish": "新しい投稿やページの公開",
"allowSignup": "ユーザーの新規登録を許可",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(変更しない場合は空白のままにしてください)",
"branding": "ブランディング",
"brandingDirectoryPath": "ブランディングのディレクトリへのパス",
diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json
index 64a6c7d5..498c0812 100644
--- a/frontend/src/i18n/ko.json
+++ b/frontend/src/i18n/ko.json
@@ -166,6 +166,7 @@
"allowNew": "파일/디렉토리 생성 허용",
"allowPublish": "새 포스트/페이지 생성 허용",
"allowSignup": "사용자 가입 허용",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(수정하지 않으면 비워두세요)",
"branding": "브랜딩",
"brandingDirectoryPath": "브랜드 디렉토리 경로",
diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json
index 78a7c281..b587a79b 100644
--- a/frontend/src/i18n/nl-be.json
+++ b/frontend/src/i18n/nl-be.json
@@ -166,6 +166,7 @@
"allowNew": "Nieuwe bestanden of mappen aanmaken",
"allowPublish": "Publiceer nieuwe berichten en pagina's",
"allowSignup": "Sta gebruikers toe om zich te registreren",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(laat leeg om wijzigingen te voorkomen)",
"branding": "Branding",
"brandingDirectoryPath": "Branding directory path",
diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json
index 3eea3638..b7a885eb 100644
--- a/frontend/src/i18n/no.json
+++ b/frontend/src/i18n/no.json
@@ -166,6 +166,7 @@
"allowNew": "Opprett nye filer og direktorater",
"allowPublish": "Publiser nye innlegg og sider",
"allowSignup": "Tilat brukere å registrere seg",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(la stå tomt for å unngå endringer)",
"branding": "Merkevarebygging",
"brandingDirectoryPath": "Bane for merkevarekatalog",
diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json
index 7c9e71b8..e34c1c07 100644
--- a/frontend/src/i18n/pl.json
+++ b/frontend/src/i18n/pl.json
@@ -166,6 +166,7 @@
"allowNew": "Tworzenie nowych plików lub folderów",
"allowPublish": "Tworzenie nowych wpisów i stron",
"allowSignup": "Pozwól użytkownikom na rejestrację",
+ "hideLoginButton": "Ukryj przycisk logowania na stronach publicznych",
"avoidChanges": "(pozostaw puste, aby uniknąć zmian)",
"branding": "Personalizacja",
"brandingDirectoryPath": "Ścieżka do folderu personalizacji",
diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json
index d29f98d6..54b8234b 100644
--- a/frontend/src/i18n/pt-br.json
+++ b/frontend/src/i18n/pt-br.json
@@ -166,6 +166,7 @@
"allowNew": "Criar novos arquivos e pastas",
"allowPublish": "Publicar novas páginas e conteúdos",
"allowSignup": "Permitir cadastro de usuários",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(deixe em branco para manter)",
"branding": "Customização",
"brandingDirectoryPath": "Diretório de customização",
diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json
index e54a4f0d..fb44edba 100644
--- a/frontend/src/i18n/pt.json
+++ b/frontend/src/i18n/pt.json
@@ -166,6 +166,7 @@
"allowNew": "Criar novos ficheiros e pastas",
"allowPublish": "Publicar novas páginas e conteúdos",
"allowSignup": "Permitir que os utilizadores criem contas",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(deixe em branco para manter)",
"branding": "Marca",
"brandingDirectoryPath": "Caminho da pasta de marca",
diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json
index 73719a4e..92c40d20 100644
--- a/frontend/src/i18n/ro.json
+++ b/frontend/src/i18n/ro.json
@@ -166,6 +166,7 @@
"allowNew": "Crează noi fișiere sau directoare",
"allowPublish": "Publică noi pagini și postări",
"allowSignup": "Permite utilizatorilor să se înregistreze",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(lasă gol pentru a nu schimba)",
"branding": "Branding",
"brandingDirectoryPath": "Calea către directorul de branding",
diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json
index 0678ce14..b3307f45 100644
--- a/frontend/src/i18n/ru.json
+++ b/frontend/src/i18n/ru.json
@@ -166,6 +166,7 @@
"allowNew": "Создание новых файлов или каталогов",
"allowPublish": "Публикация новых записей и страниц",
"allowSignup": "Разрешить пользователям регистрироваться",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(оставьте поле пустым, чтобы избежать изменений)",
"branding": "Брендинг",
"brandingDirectoryPath": "Путь к каталогу брендов",
diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json
index da0fac33..95a34486 100644
--- a/frontend/src/i18n/sk.json
+++ b/frontend/src/i18n/sk.json
@@ -166,6 +166,7 @@
"allowNew": "Vytvárať nové súbory a priečinky",
"allowPublish": "Zverejňovať nové príspevky a stránky",
"allowSignup": "Povoliť registráciu používateľov",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(nechajte prázdne, aby sa nezmenilo)",
"branding": "Vlastný vzhľad",
"brandingDirectoryPath": "Cesta k priečinku s vlastným vzhľadom",
diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json
index 0378587a..e4e89911 100644
--- a/frontend/src/i18n/sv-se.json
+++ b/frontend/src/i18n/sv-se.json
@@ -166,6 +166,7 @@
"allowNew": "Skapa nya filer eller mappar",
"allowPublish": "Publicera nya inlägg och sidor",
"allowSignup": "Tillåt användare att registrera sig",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(lämna blankt för att undvika ändringar)",
"branding": "Varumärke",
"brandingDirectoryPath": "Sökväg till varumärkes katalog",
diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json
index 7493821e..6d3fbc5c 100644
--- a/frontend/src/i18n/tr.json
+++ b/frontend/src/i18n/tr.json
@@ -166,6 +166,7 @@
"allowNew": "Yeni dosyalar ve dizinler oluşturun",
"allowPublish": "Yeni linkler ve sayfaları yayınlayın",
"allowSignup": "Kullanıcıların kaydolmasına izin ver",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(değişiklikleri önlemek için boş bırakın)",
"branding": "Marka",
"brandingDirectoryPath": "Marka dizin yolu",
diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json
index 40a96893..3c78b228 100644
--- a/frontend/src/i18n/uk.json
+++ b/frontend/src/i18n/uk.json
@@ -166,6 +166,7 @@
"allowNew": "Створення нових файлів або каталогів",
"allowPublish": "Публікація нових записів та сторінок",
"allowSignup": "Дозволити користувачам реєструватися",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(залишіть поле порожнім, щоб уникнути змін)",
"branding": "Брендинг",
"brandingDirectoryPath": "Шлях до каталогу брендів",
diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json
index fab93759..aa2a5279 100644
--- a/frontend/src/i18n/vi.json
+++ b/frontend/src/i18n/vi.json
@@ -166,6 +166,7 @@
"allowNew": "Tạo tệp và thư mục mới",
"allowPublish": "Xuất bản bài viết và trang mới",
"allowSignup": "Cho phép người dùng đăng ký",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(để trống để tránh thay đổi)",
"branding": "Thương hiệu",
"brandingDirectoryPath": "Đường dẫn thư mục thương hiệu",
diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json
index 15cf8e3c..def97e9a 100644
--- a/frontend/src/i18n/zh-cn.json
+++ b/frontend/src/i18n/zh-cn.json
@@ -166,6 +166,7 @@
"allowNew": "创建新文件和文件夹",
"allowPublish": "发布新的帖子与页面",
"allowSignup": "允许用户注册",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(留空以避免更改)",
"branding": "品牌",
"brandingDirectoryPath": "品牌信息文件夹路径",
diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json
index d59f1efd..4644ad90 100644
--- a/frontend/src/i18n/zh-tw.json
+++ b/frontend/src/i18n/zh-tw.json
@@ -166,6 +166,7 @@
"allowNew": "建立新檔案和目錄",
"allowPublish": "發佈新的貼文與頁面",
"allowSignup": "允許使用者註冊",
+ "hideLoginButton": "Hide the login button from public pages",
"avoidChanges": "(留空以避免更改)",
"branding": "品牌",
"brandingDirectoryPath": "品牌資訊資料夾路徑",
From ce3b407c51319f95cc6c7936ed87b5b2a1e3e01a Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Fri, 14 Nov 2025 17:49:52 +0100
Subject: [PATCH 009/120] docs: clarify status
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 33ecbde1..1e15d592 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ This project is a finished product which fulfills its goal: be a single binary w
- It can take a while until someone gets back to you. Please be patient.
- [Issues](https://github.com/filebrowser/filebrowser/issues) are meant to track bugs. Unrelated issues will be converted into [discussions](https://github.com/filebrowser/filebrowser/discussions).
- No new features will be implemented by maintainers. Pull requests for new features will be reviewed on a case by case basis.
-- The priority is triaging issues, addressing security issues, and fixing bug fixes.
+- The priority is triaging issues, addressing security issues and reviewing pull requests meant to solve bugs.
## Contributing
From 4e9e312984402b5d0214992f16f79c6e82fa9213 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Fri, 14 Nov 2025 18:15:33 +0100
Subject: [PATCH 010/120] chore(release): 2.46.0
---
CHANGELOG.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2be8b2c8..7b21953d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,16 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [2.46.0](https://github.com/filebrowser/filebrowser/compare/v2.45.3...v2.46.0) (2025-11-14)
+
+
+### Features
+
+* add 'hide-dotfiles' as command line parameter ([#3802](https://github.com/filebrowser/filebrowser/issues/3802)) ([0d973d3](https://github.com/filebrowser/filebrowser/commit/0d973d3aad70ceb88950f2cd9c297fc76e7955b1))
+* add context menu ([#3343](https://github.com/filebrowser/filebrowser/issues/3343)) ([1ace579](https://github.com/filebrowser/filebrowser/commit/1ace579a553486bb15af2d11f537414156606434))
+* add option to hide the login button from public-facing pages ([#3922](https://github.com/filebrowser/filebrowser/issues/3922)) ([ac7b49c](https://github.com/filebrowser/filebrowser/commit/ac7b49c1484b4e27a1149310542ccd1e90659ee2))
+* Updates for project File Browser ([#5544](https://github.com/filebrowser/filebrowser/issues/5544)) ([fb5d099](https://github.com/filebrowser/filebrowser/commit/fb5d099f8514516216f407be012d2e3f25de2441))
+
## [2.45.3](https://github.com/filebrowser/filebrowser/compare/v2.45.2...v2.45.3) (2025-11-13)
This is a test release to ensure the updated workflow works.
From 13814e11197ebd9101940883e3ca85998f86d442 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sat, 15 Nov 2025 08:40:37 +0100
Subject: [PATCH 011/120] fix: env key replacer and remove unused function
(#5547)
---
cmd/root.go | 3 +--
cmd/utils.go | 16 +++-------------
2 files changed, 4 insertions(+), 15 deletions(-)
diff --git a/cmd/root.go b/cmd/root.go
index 8f793742..d8be251a 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -534,8 +534,7 @@ func initConfig() {
v.SetEnvPrefix("FB")
v.AutomaticEnv()
- v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
- v.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
+ v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
if err := v.ReadInConfig(); err != nil {
var configParseError v.ConfigParseError
diff --git a/cmd/utils.go b/cmd/utils.go
index 1971afd4..8e5168af 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -23,16 +23,8 @@ import (
const dbPerms = 0640
-func returnErr(err error) error {
- if err != nil {
- return err
- }
- return nil
-}
-
func getString(flags *pflag.FlagSet, flag string) (string, error) {
- s, err := flags.GetString(flag)
- return s, returnErr(err)
+ return flags.GetString(flag)
}
func getMode(flags *pflag.FlagSet, flag string) (fs.FileMode, error) {
@@ -48,13 +40,11 @@ func getMode(flags *pflag.FlagSet, flag string) (fs.FileMode, error) {
}
func getBool(flags *pflag.FlagSet, flag string) (bool, error) {
- b, err := flags.GetBool(flag)
- return b, returnErr(err)
+ return flags.GetBool(flag)
}
func getUint(flags *pflag.FlagSet, flag string) (uint, error) {
- b, err := flags.GetUint(flag)
- return b, returnErr(err)
+ return flags.GetUint(flag)
}
func generateKey() []byte {
From ffc850454e4cb8f10b970511681d6c627340afc7 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sat, 15 Nov 2025 08:50:22 +0100
Subject: [PATCH 012/120] fix: remove duplicated 'hide-defaults' flag (is
'hideDefaults') (#5548)
---
cmd/users.go | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/cmd/users.go b/cmd/users.go
index 64cd08ee..c272877d 100644
--- a/cmd/users.go
+++ b/cmd/users.go
@@ -80,7 +80,6 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.Bool("dateFormat", false, "use date format (true for absolute time, false for relative)")
flags.Bool("hideDotfiles", false, "hide dotfiles")
flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users")
- flags.Bool("hide-dotfiles", false, "Hide dotfiles by default")
}
func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) {
@@ -136,7 +135,7 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
defaults.Sorting.By, err = getString(flags, flag.Name)
case "sorting.asc":
defaults.Sorting.Asc, err = getBool(flags, flag.Name)
- case "hide-dotfiles":
+ case "hideDotfiles":
defaults.HideDotfiles, err = getBool(flags, flag.Name)
}
if err != nil {
From 17f1e08a5877654d0dd24ce6df355b64db66234a Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sat, 15 Nov 2025 08:51:04 +0100
Subject: [PATCH 013/120] chore(release): 2.46.1
---
CHANGELOG.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7b21953d..70d61c71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [2.46.1](https://github.com/filebrowser/filebrowser/compare/v2.46.0...v2.46.1) (2025-11-15)
+
+
+### Bug Fixes
+
+* env key replacer and remove unused function ([#5547](https://github.com/filebrowser/filebrowser/issues/5547)) ([13814e1](https://github.com/filebrowser/filebrowser/commit/13814e11197ebd9101940883e3ca85998f86d442))
+* remove duplicated 'hide-defaults' flag (is 'hideDefaults') ([#5548](https://github.com/filebrowser/filebrowser/issues/5548)) ([ffc8504](https://github.com/filebrowser/filebrowser/commit/ffc850454e4cb8f10b970511681d6c627340afc7))
+
## [2.46.0](https://github.com/filebrowser/filebrowser/compare/v2.45.3...v2.46.0) (2025-11-14)
From 23c4e4565ba252d558b01f76c7c8c8bc5b885e85 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sat, 15 Nov 2025 09:01:21 +0100
Subject: [PATCH 014/120] chore: remove 'nolint' comments
---
auth/hook.go | 2 +-
auth/json.go | 2 +-
cmd/root.go | 11 +++++------
cmd/users.go | 1 -
cmd/users_import.go | 2 +-
cmd/utils.go | 2 +-
diskcache/file_cache.go | 4 ++--
diskcache/file_cache_test.go | 2 +-
files/file.go | 7 +++----
files/mime.go | 1 -
http/commands.go | 11 +++++------
http/public_test.go | 4 ++--
http/share.go | 1 -
http/static.go | 4 ++--
img/service.go | 2 +-
runner/runner.go | 4 ++--
users/assets.go | 1 -
users/storage.go | 2 +-
users/users.go | 4 +---
19 files changed, 29 insertions(+), 38 deletions(-)
diff --git a/auth/hook.go b/auth/hook.go
index 2ecb12f3..ec3c5bfb 100644
--- a/auth/hook.go
+++ b/auth/hook.go
@@ -103,7 +103,7 @@ func (a *HookAuth) RunCommand() (string, error) {
command[i] = os.Expand(arg, envMapping)
}
- cmd := exec.Command(command[0], command[1:]...) //nolint:gosec
+ cmd := exec.Command(command[0], command[1:]...)
cmd.Env = append(os.Environ(), fmt.Sprintf("USERNAME=%s", a.Cred.Username))
cmd.Env = append(cmd.Env, fmt.Sprintf("PASSWORD=%s", a.Cred.Password))
out, err := cmd.Output()
diff --git a/auth/json.go b/auth/json.go
index 81f430b3..f779c476 100644
--- a/auth/json.go
+++ b/auth/json.go
@@ -40,7 +40,7 @@ func (a JSONAuth) Auth(r *http.Request, usr users.Store, _ *settings.Settings, s
// If ReCaptcha is enabled, check the code.
if a.ReCaptcha != nil && a.ReCaptcha.Secret != "" {
- ok, err := a.ReCaptcha.Ok(cred.ReCaptcha) //nolint:govet
+ ok, err := a.ReCaptcha.Ok(cred.ReCaptcha)
if err != nil {
return nil, err
diff --git a/cmd/root.go b/cmd/root.go
index d8be251a..24f5d077 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -70,7 +70,7 @@ func addServerFlags(flags *pflag.FlagSet) {
flags.StringP("baseurl", "b", "", "base url")
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
flags.String("token-expiration-time", "2h", "user session timeout")
- flags.Int("img-processors", 4, "image processors count") //nolint:mnd
+ flags.Int("img-processors", 4, "image processors count")
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
flags.Bool("disable-preview-resize", false, "disable resize of image previews")
flags.Bool("disable-exec", true, "disables Command Runner feature")
@@ -141,7 +141,7 @@ user created with the credentials from options "username" and "password".`,
return err
}
if cacheDir != "" {
- if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet
+ if err := os.MkdirAll(cacheDir, 0700); err != nil {
return fmt.Errorf("can't make directory %s: %w", cacheDir, err)
}
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
@@ -169,7 +169,7 @@ user created with the credentials from options "username" and "password".`,
if err != nil {
return err
}
- socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet
+ socketPerm, err := cmd.Flags().GetUint32("socket-perm")
if err != nil {
return err
}
@@ -178,7 +178,7 @@ user created with the credentials from options "username" and "password".`,
return err
}
case server.TLSKey != "" && server.TLSCert != "":
- cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:govet
+ cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey)
if err != nil {
return err
}
@@ -233,7 +233,7 @@ user created with the credentials from options "username" and "password".`,
sig := <-sigc
log.Println("Got signal:", sig)
- shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second) //nolint:mnd
+ shutdownCtx, shutdownRelease := context.WithTimeout(context.Background(), 10*time.Second)
defer shutdownRelease()
if err := srv.Shutdown(shutdownCtx); err != nil {
@@ -256,7 +256,6 @@ user created with the credentials from options "username" and "password".`,
}, pythonConfig{allowNoDB: true}),
}
-//nolint:gocyclo
func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server, error) {
server, err := st.Settings.GetServer()
if err != nil {
diff --git a/cmd/users.go b/cmd/users.go
index c272877d..c2e2ce1e 100644
--- a/cmd/users.go
+++ b/cmd/users.go
@@ -94,7 +94,6 @@ func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) {
return viewMode, nil
}
-//nolint:gocyclo
func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all bool) error {
var visitErr error
visit := func(flag *pflag.Flag) {
diff --git a/cmd/users_import.go b/cmd/users_import.go
index d20dca68..74353c2c 100644
--- a/cmd/users_import.go
+++ b/cmd/users_import.go
@@ -87,7 +87,7 @@ list or set it to 0.`,
// with the new username. If there is, print an error and cancel the
// operation
if user.Username != onDB.Username {
- if conflictuous, err := d.store.Users.Get("", user.Username); err == nil { //nolint:govet
+ if conflictuous, err := d.store.Users.Get("", user.Username); err == nil {
return usernameConflictError(user.Username, conflictuous.ID, user.ID)
}
}
diff --git a/cmd/utils.go b/cmd/utils.go
index 8e5168af..cc718341 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -79,7 +79,7 @@ func dbExists(path string) (bool, error) {
d := filepath.Dir(path)
_, err = os.Stat(d)
if os.IsNotExist(err) {
- if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet
+ if err := os.MkdirAll(d, 0700); err != nil {
return false, err
}
return false, nil
diff --git a/diskcache/file_cache.go b/diskcache/file_cache.go
index cd5e27c7..b2979e4b 100644
--- a/diskcache/file_cache.go
+++ b/diskcache/file_cache.go
@@ -2,7 +2,7 @@ package diskcache
import (
"context"
- "crypto/sha1" //nolint:gosec
+ "crypto/sha1"
"encoding/hex"
"errors"
"fmt"
@@ -103,7 +103,7 @@ func (f *FileCache) getScopedLocks(key string) (lock sync.Locker) {
}
func (f *FileCache) getFileName(key string) string {
- hasher := sha1.New() //nolint:gosec
+ hasher := sha1.New()
_, _ = hasher.Write([]byte(key))
hash := hex.EncodeToString(hasher.Sum(nil))
return fmt.Sprintf("%s/%s/%s", hash[:1], hash[1:3], hash)
diff --git a/diskcache/file_cache_test.go b/diskcache/file_cache_test.go
index 31d58c8e..9a41052e 100644
--- a/diskcache/file_cache_test.go
+++ b/diskcache/file_cache_test.go
@@ -40,7 +40,7 @@ func TestFileCache(t *testing.T) {
require.False(t, exists)
}
-func checkValue(t *testing.T, ctx context.Context, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) { //nolint:revive
+func checkValue(t *testing.T, ctx context.Context, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) {
t.Helper()
// check actual file content
b, err := afero.ReadFile(fs, fileFullPath)
diff --git a/files/file.go b/files/file.go
index 8e27e549..0f96440e 100644
--- a/files/file.go
+++ b/files/file.go
@@ -1,8 +1,8 @@
package files
import (
- "crypto/md5" //nolint:gosec
- "crypto/sha1" //nolint:gosec
+ "crypto/md5"
+ "crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/hex"
@@ -90,7 +90,7 @@ func NewFileInfo(opts *FileOptions) (*FileInfo, error) {
if opts.Expand {
if file.IsDir {
- if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { //nolint:govet
+ if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil {
return nil, err
}
return file, nil
@@ -183,7 +183,6 @@ func (i *FileInfo) Checksum(algo string) error {
var h hash.Hash
- //nolint:gosec
switch algo {
case "md5":
h = md5.New()
diff --git a/files/mime.go b/files/mime.go
index 33fd93bd..baa4d6d5 100644
--- a/files/mime.go
+++ b/files/mime.go
@@ -600,7 +600,6 @@ var types = map[string]string{
".epub": "application/epub+zip",
}
-//nolint:gochecknoinits
func init() {
for ext, typ := range types {
// skip errors
diff --git a/http/commands.go b/http/commands.go
index 1da1f75c..6229d597 100644
--- a/http/commands.go
+++ b/http/commands.go
@@ -28,7 +28,6 @@ var (
cmdNotAllowed = []byte("Command not allowed.")
)
-//nolint:unparam
func wsErr(ws *websocket.Conn, r *http.Request, status int, err error) {
txt := http.StatusText(status)
if err != nil || status >= 400 {
@@ -49,7 +48,7 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d
var raw string
for {
- _, msg, err := conn.ReadMessage() //nolint:govet
+ _, msg, err := conn.ReadMessage()
if err != nil {
wsErr(conn, r, http.StatusInternalServerError, err)
return 0, nil
@@ -63,7 +62,7 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d
// Fail fast
if !d.server.EnableExec || !d.user.Perm.Execute {
- if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil { //nolint:govet
+ if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil {
wsErr(conn, r, http.StatusInternalServerError, err)
}
@@ -72,21 +71,21 @@ var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *d
command, name, err := runner.ParseCommand(d.settings, raw)
if err != nil {
- if err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())); err != nil { //nolint:govet
+ if err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())); err != nil {
wsErr(conn, r, http.StatusInternalServerError, err)
}
return 0, nil
}
if !slices.Contains(d.user.Commands, name) {
- if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil { //nolint:govet
+ if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil {
wsErr(conn, r, http.StatusInternalServerError, err)
}
return 0, nil
}
- cmd := exec.Command(command[0], command[1:]...) //nolint:gosec
+ cmd := exec.Command(command[0], command[1:]...)
cmd.Dir = d.user.FullPath(r.URL.Path)
stdout, err := cmd.StdoutPipe()
diff --git a/http/public_test.go b/http/public_test.go
index 9f89cbc0..f102cc07 100644
--- a/http/public_test.go
+++ b/http/public_test.go
@@ -19,7 +19,7 @@ import (
func TestPublicShareHandlerAuthentication(t *testing.T) {
t.Parallel()
- const passwordBcrypt = "$2y$10$TFAmdCbyd/mEZDe5fUeZJu.MaJQXRTwdqb/IQV.eTn6dWrF58gCSe" //nolint:gosec
+ const passwordBcrypt = "$2y$10$TFAmdCbyd/mEZDe5fUeZJu.MaJQXRTwdqb/IQV.eTn6dWrF58gCSe"
testCases := map[string]struct {
share *share.Link
req *http.Request
@@ -70,7 +70,7 @@ func TestPublicShareHandlerAuthentication(t *testing.T) {
}
t.Cleanup(func() {
- if err := db.Close(); err != nil { //nolint:govet
+ if err := db.Close(); err != nil {
t.Errorf("failed to close db: %v", err)
}
})
diff --git a/http/share.go b/http/share.go
index d968c05b..670629bd 100644
--- a/http/share.go
+++ b/http/share.go
@@ -111,7 +111,6 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
var expire int64 = 0
if body.Expires != "" {
- //nolint:govet
num, err := strconv.Atoi(body.Expires)
if err != nil {
return http.StatusInternalServerError, err
diff --git a/http/static.go b/http/static.go
index 5a52940d..be2c135c 100644
--- a/http/static.go
+++ b/http/static.go
@@ -51,7 +51,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
if d.settings.Branding.Files != "" {
fPath := filepath.Join(d.settings.Branding.Files, "custom.css")
- _, err := os.Stat(fPath) //nolint:govet
+ _, err := os.Stat(fPath)
if err != nil && !os.IsNotExist(err) {
log.Printf("couldn't load custom styles: %v", err)
@@ -63,7 +63,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
}
if d.settings.AuthMethod == auth.MethodJSONAuth {
- raw, err := d.store.Auth.Get(d.settings.AuthMethod) //nolint:govet
+ raw, err := d.store.Auth.Get(d.settings.AuthMethod)
if err != nil {
return http.StatusInternalServerError, err
}
diff --git a/img/service.go b/img/service.go
index 34a84c67..47aaddca 100644
--- a/img/service.go
+++ b/img/service.go
@@ -184,7 +184,7 @@ func (s *Service) Resize(ctx context.Context, in io.Reader, width, height int, o
case ResizeModeFill:
img = imaging.Fill(img, width, height, imaging.Center, config.quality.resampleFilter())
case ResizeModeFit:
- fallthrough //nolint:gocritic
+ fallthrough
default:
img = imaging.Fit(img, width, height, config.quality.resampleFilter())
}
diff --git a/runner/runner.go b/runner/runner.go
index 00e7c16a..3408a1ee 100644
--- a/runner/runner.go
+++ b/runner/runner.go
@@ -89,9 +89,9 @@ func (r *Runner) exec(raw, evt, path, dst string, user *users.User) error {
command[i] = os.Expand(arg, envMapping)
}
- cmd := exec.Command(command[0], command[1:]...) //nolint:gosec
+ cmd := exec.Command(command[0], command[1:]...)
cmd.Env = append(os.Environ(), fmt.Sprintf("FILE=%s", path))
- cmd.Env = append(cmd.Env, fmt.Sprintf("SCOPE=%s", user.Scope)) //nolint:gocritic
+ cmd.Env = append(cmd.Env, fmt.Sprintf("SCOPE=%s", user.Scope))
cmd.Env = append(cmd.Env, fmt.Sprintf("TRIGGER=%s", evt))
cmd.Env = append(cmd.Env, fmt.Sprintf("USERNAME=%s", user.Username))
cmd.Env = append(cmd.Env, fmt.Sprintf("DESTINATION=%s", dst))
diff --git a/users/assets.go b/users/assets.go
index a01aed41..7b09580d 100644
--- a/users/assets.go
+++ b/users/assets.go
@@ -9,7 +9,6 @@ import (
var assets embed.FS
var commonPasswords map[string]struct{}
-//nolint:gochecknoinits
func init() {
// Password list sourced from:
// https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt
diff --git a/users/storage.go b/users/storage.go
index 163082fb..1dd0da3f 100644
--- a/users/storage.go
+++ b/users/storage.go
@@ -63,7 +63,7 @@ func (s *Storage) Gets(baseScope string) ([]*User, error) {
}
for _, user := range users {
- if err := user.Clean(baseScope); err != nil { //nolint:govet
+ if err := user.Clean(baseScope); err != nil {
return nil, err
}
}
diff --git a/users/users.go b/users/users.go
index 020faf11..987a94f2 100644
--- a/users/users.go
+++ b/users/users.go
@@ -55,8 +55,6 @@ var checkableFields = []string{
// Clean cleans up a user and verifies if all its fields
// are alright to be saved.
-//
-//nolint:gocyclo
func (u *User) Clean(baseScope string, fields ...string) error {
if len(fields) == 0 {
fields = checkableFields
@@ -93,7 +91,7 @@ func (u *User) Clean(baseScope string, fields ...string) error {
if u.Fs == nil {
scope := u.Scope
- scope = filepath.Join(baseScope, filepath.Join("/", scope)) //nolint:gocritic
+ scope = filepath.Join(baseScope, filepath.Join("/", scope))
u.Fs = afero.NewBasePathFs(afero.NewOsFs(), scope)
}
From ebc7d2303d7994941691a14c55ec6df66df9e9f9 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 15 Nov 2025 20:14:10 +0100
Subject: [PATCH 015/120] chore(deps): update dependency vue-tsc to v3.1.4
(#5551)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/pnpm-lock.yaml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 4f4907ee..db9de505 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -161,7 +161,7 @@ importers:
version: 2.3.1(rollup@4.52.5)
vue-tsc:
specifier: ^3.1.3
- version: 3.1.3(typescript@5.9.3)
+ version: 3.1.4(typescript@5.9.3)
packages:
@@ -1303,8 +1303,8 @@ packages:
typescript:
optional: true
- '@vue/language-core@3.1.3':
- resolution: {integrity: sha512-KpR1F/eGAG9D1RZ0/T6zWJs6dh/pRLfY5WupecyYKJ1fjVmDMgTPw9wXmKv2rBjo4zCJiOSiyB8BDP1OUwpMEA==}
+ '@vue/language-core@3.1.4':
+ resolution: {integrity: sha512-n/58wm8SkmoxMWkUNUH/PwoovWe4hmdyPJU2ouldr3EPi1MLoS7iDN46je8CsP95SnVBs2axInzRglPNKvqMcg==}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
@@ -2484,8 +2484,8 @@ packages:
peerDependencies:
vue: ^3.0.2
- vue-tsc@3.1.3:
- resolution: {integrity: sha512-StMNfZHwPIXQgY3KxPKM0Jsoc8b46mDV3Fn2UlHCBIwRJApjqrSwqeMYgWf0zpN+g857y74pv7GWuBm+UqQe1w==}
+ vue-tsc@3.1.4:
+ resolution: {integrity: sha512-GsRJxttj4WkmXW/zDwYPGMJAN3np/4jTzoDFQTpTsI5Vg/JKMWamBwamlmLihgSVHO66y9P7GX+uoliYxeI4Hw==}
hasBin: true
peerDependencies:
typescript: '>=5.0.0'
@@ -3828,7 +3828,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vue/language-core@3.1.3(typescript@5.9.3)':
+ '@vue/language-core@3.1.4(typescript@5.9.3)':
dependencies:
'@volar/language-core': 2.4.23
'@vue/compiler-dom': 3.5.24
@@ -4966,10 +4966,10 @@ snapshots:
dependencies:
vue: 3.5.24(typescript@5.9.3)
- vue-tsc@3.1.3(typescript@5.9.3):
+ vue-tsc@3.1.4(typescript@5.9.3):
dependencies:
'@volar/typescript': 2.4.23
- '@vue/language-core': 3.1.3(typescript@5.9.3)
+ '@vue/language-core': 3.1.4(typescript@5.9.3)
typescript: 5.9.3
vue@3.5.24(typescript@5.9.3):
From ceb5e723f3ee2c966bb561a804015246450280ca Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 07:52:53 +0100
Subject: [PATCH 016/120] feat: remove importer of v1 config (#5550)
---
cmd/upgrade.go | 40 -------
go.mod | 4 +-
storage/bolt/importer/conf.go | 187 ------------------------------
storage/bolt/importer/importer.go | 39 -------
storage/bolt/importer/users.go | 114 ------------------
5 files changed, 2 insertions(+), 382 deletions(-)
delete mode 100644 cmd/upgrade.go
delete mode 100644 storage/bolt/importer/conf.go
delete mode 100644 storage/bolt/importer/importer.go
delete mode 100644 storage/bolt/importer/users.go
diff --git a/cmd/upgrade.go b/cmd/upgrade.go
deleted file mode 100644
index 7142b151..00000000
--- a/cmd/upgrade.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package cmd
-
-import (
- "github.com/spf13/cobra"
-
- "github.com/filebrowser/filebrowser/v2/storage/bolt/importer"
-)
-
-func init() {
- rootCmd.AddCommand(upgradeCmd)
-
- upgradeCmd.Flags().String("old.database", "", "")
- upgradeCmd.Flags().String("old.config", "", "")
- _ = upgradeCmd.MarkFlagRequired("old.database")
-}
-
-var upgradeCmd = &cobra.Command{
- Use: "upgrade",
- Short: "Upgrades an old configuration",
- Long: `Upgrades an old configuration. This command DOES NOT
-import share links because they are incompatible with
-this version.`,
- Args: cobra.NoArgs,
- RunE: func(cmd *cobra.Command, _ []string) error {
- flags := cmd.Flags()
- oldDB, err := getString(flags, "old.database")
- if err != nil {
- return err
- }
- oldConf, err := getString(flags, "old.config")
- if err != nil {
- return err
- }
- db, err := getString(flags, "database")
- if err != nil {
- return err
- }
- return importer.Import(oldDB, oldConf, db)
- },
-}
diff --git a/go.mod b/go.mod
index 7736fe11..724b0c8f 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,6 @@ require (
github.com/marusama/semaphore/v2 v2.5.0
github.com/mholt/archives v0.1.5
github.com/mitchellh/go-homedir v1.1.0
- github.com/pelletier/go-toml/v2 v2.2.4
github.com/shirou/gopsutil/v4 v4.25.10
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.1
@@ -24,7 +23,6 @@ require (
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
- go.etcd.io/bbolt v1.4.3
golang.org/x/crypto v0.44.0
golang.org/x/image v0.33.0
golang.org/x/text v0.31.0
@@ -58,6 +56,7 @@ require (
github.com/mikelolasagasti/xz v1.0.1 // indirect
github.com/minio/minlz v1.0.1 // indirect
github.com/nwaples/rardecode/v2 v2.2.0 // indirect
+ github.com/pelletier/go-toml/v2 v2.2.4 // 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
@@ -68,6 +67,7 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ go.etcd.io/bbolt v1.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
golang.org/x/net v0.46.0 // indirect
diff --git a/storage/bolt/importer/conf.go b/storage/bolt/importer/conf.go
deleted file mode 100644
index b3ac0ba7..00000000
--- a/storage/bolt/importer/conf.go
+++ /dev/null
@@ -1,187 +0,0 @@
-package importer
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "os"
- "path/filepath"
-
- "github.com/asdine/storm/v3"
- "github.com/pelletier/go-toml/v2"
- "gopkg.in/yaml.v3"
-
- "github.com/filebrowser/filebrowser/v2/auth"
- "github.com/filebrowser/filebrowser/v2/settings"
- "github.com/filebrowser/filebrowser/v2/storage"
- "github.com/filebrowser/filebrowser/v2/users"
-)
-
-type oldDefs struct {
- Commands []string `json:"commands" yaml:"commands" toml:"commands"`
- Scope string `json:"scope" yaml:"scope" toml:"scope"`
- ViewMode string `json:"viewMode" yaml:"viewMode" toml:"viewMode"`
- Locale string `json:"locale" yaml:"locale" toml:"locale"`
- AllowCommands bool `json:"allowCommands" yaml:"allowCommands" toml:"allowCommands"`
- AllowEdit bool `json:"allowEdit" yaml:"allowEdit" toml:"allowEdit"`
- AllowNew bool `json:"allowNew" yaml:"allowNew" toml:"allowNew"`
-}
-
-type oldAuth struct {
- Method string `json:"method" yaml:"method" toml:"method"` // default none proxy
- Header string `json:"header" yaml:"header" toml:"header"`
- Command string `json:"command" yaml:"command" toml:"command"`
-}
-
-type oldConf struct {
- Port string `json:"port" yaml:"port" toml:"port"`
- BaseURL string `json:"baseURL" yaml:"baseURL" toml:"baseURL"`
- Log string `json:"log" yaml:"log" toml:"log"`
- Address string `json:"address" yaml:"address" toml:"address"`
- Defaults oldDefs `json:"defaults" yaml:"defaults" toml:"defaults"`
- ReCaptcha struct {
- Key string `json:"key" yaml:"key" toml:"key"`
- Secret string `json:"secret" yaml:"secret" toml:"secret"`
- Host string `json:"host" yaml:"host" toml:"host"`
- } `json:"recaptcha" yaml:"recaptcha" toml:"recaptcha"`
- Auth oldAuth `json:"auth" yaml:"auth" toml:"auth"`
-}
-
-var defaults = &oldConf{
- Port: "0",
- Log: "stdout",
- Defaults: oldDefs{
- Commands: []string{"git", "svn", "hg"},
- ViewMode: string(users.MosaicViewMode),
- AllowCommands: true,
- AllowEdit: true,
- AllowNew: true,
- Locale: "en",
- },
- Auth: oldAuth{
- Method: "default",
- },
-}
-
-func readConf(path string) (*oldConf, error) {
- cfg := &oldConf{}
- if path != "" {
- ext := filepath.Ext(path)
-
- fd, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer fd.Close()
-
- switch ext {
- case ".json":
- err = json.NewDecoder(fd).Decode(cfg)
- case ".toml":
- err = toml.NewDecoder(fd).Decode(cfg)
- case ".yaml", ".yml":
- err = yaml.NewDecoder(fd).Decode(cfg)
- default:
- return nil, errors.New("unsupported config extension " + ext)
- }
-
- if err != nil {
- return nil, err
- }
- } else {
- cfg = defaults
- path, err := filepath.Abs(".")
- if err != nil {
- return nil, err
- }
- cfg.Defaults.Scope = path
- }
- return cfg, nil
-}
-
-func importConf(db *storm.DB, path string, sto *storage.Storage) error {
- cfg, err := readConf(path)
- if err != nil {
- return err
- }
-
- commands := map[string][]string{}
- err = db.Get("config", "commands", &commands)
- if err != nil {
- return err
- }
-
- key := []byte{}
- err = db.Get("config", "key", &key)
- if err != nil {
- return err
- }
-
- s := &settings.Settings{
- Key: key,
- Signup: false,
- Defaults: settings.UserDefaults{
- Scope: cfg.Defaults.Scope,
- Commands: cfg.Defaults.Commands,
- ViewMode: users.ViewMode(cfg.Defaults.ViewMode),
- Locale: cfg.Defaults.Locale,
- Perm: users.Permissions{
- Admin: false,
- Execute: cfg.Defaults.AllowCommands,
- Create: cfg.Defaults.AllowNew,
- Rename: cfg.Defaults.AllowEdit,
- Modify: cfg.Defaults.AllowEdit,
- Delete: cfg.Defaults.AllowEdit,
- Share: true,
- Download: true,
- },
- },
- }
-
- server := &settings.Server{
- BaseURL: cfg.BaseURL,
- Port: cfg.Port,
- Address: cfg.Address,
- Log: cfg.Log,
- }
-
- var auther auth.Auther
- switch cfg.Auth.Method {
- case "proxy":
- auther = &auth.ProxyAuth{Header: cfg.Auth.Header}
- s.AuthMethod = auth.MethodProxyAuth
- case "hook":
- auther = &auth.HookAuth{Command: cfg.Auth.Command}
- s.AuthMethod = auth.MethodHookAuth
- case "none":
- auther = &auth.NoAuth{}
- s.AuthMethod = auth.MethodNoAuth
- default:
- auther = &auth.JSONAuth{
- ReCaptcha: &auth.ReCaptcha{
- Host: cfg.ReCaptcha.Host,
- Key: cfg.ReCaptcha.Key,
- Secret: cfg.ReCaptcha.Secret,
- },
- }
- s.AuthMethod = auth.MethodJSONAuth
- }
-
- err = sto.Auth.Save(auther)
- if err != nil {
- return err
- }
-
- err = sto.Settings.Save(s)
- if err != nil {
- return err
- }
-
- err = sto.Settings.SaveServer(server)
- if err != nil {
- return err
- }
-
- fmt.Println("Configuration successfully imported.")
- return nil
-}
diff --git a/storage/bolt/importer/importer.go b/storage/bolt/importer/importer.go
deleted file mode 100644
index 9c737756..00000000
--- a/storage/bolt/importer/importer.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package importer
-
-import (
- "github.com/asdine/storm/v3"
-
- "github.com/filebrowser/filebrowser/v2/storage/bolt"
-)
-
-// Import imports an old configuration to a newer database.
-func Import(oldDBPath, oldConf, newDBPath string) error {
- oldDB, err := storm.Open(oldDBPath)
- if err != nil {
- return err
- }
- defer oldDB.Close()
-
- newDB, err := storm.Open(newDBPath)
- if err != nil {
- return err
- }
- defer newDB.Close()
-
- sto, err := bolt.NewStorage(newDB)
- if err != nil {
- return err
- }
-
- err = importUsers(oldDB, sto)
- if err != nil {
- return err
- }
-
- err = importConf(oldDB, oldConf, sto)
- if err != nil {
- return err
- }
-
- return err
-}
diff --git a/storage/bolt/importer/users.go b/storage/bolt/importer/users.go
deleted file mode 100644
index 1b442147..00000000
--- a/storage/bolt/importer/users.go
+++ /dev/null
@@ -1,114 +0,0 @@
-package importer
-
-import (
- "encoding/json"
- "fmt"
-
- "github.com/asdine/storm/v3"
- bolt "go.etcd.io/bbolt"
-
- "github.com/filebrowser/filebrowser/v2/rules"
- "github.com/filebrowser/filebrowser/v2/storage"
- "github.com/filebrowser/filebrowser/v2/users"
-)
-
-type oldUser struct {
- ID int `storm:"id,increment"`
- Admin bool `json:"admin"`
- AllowCommands bool `json:"allowCommands"` // Execute commands
- AllowEdit bool `json:"allowEdit"` // Edit/rename files
- AllowNew bool `json:"allowNew"` // Create files and folders
- AllowPublish bool `json:"allowPublish"` // Publish content (to use with static gen)
- LockPassword bool `json:"lockPassword"`
- Commands []string `json:"commands"`
- Locale string `json:"locale"`
- Password string `json:"password"`
- Rules []*rules.Rule `json:"rules"`
- Scope string `json:"filesystem"`
- Username string `json:"username" storm:"index,unique"`
- ViewMode string `json:"viewMode"`
-}
-
-func readOldUsers(db *storm.DB) ([]*oldUser, error) {
- var oldUsers []*oldUser
- err := db.Bolt.View(func(tx *bolt.Tx) error {
- return tx.Bucket([]byte("User")).ForEach(func(_ []byte, v []byte) error {
- if len(v) > 0 && string(v)[0] == '{' {
- user := &oldUser{}
- err := json.Unmarshal(v, user)
-
- if err != nil {
- return err
- }
-
- oldUsers = append(oldUsers, user)
- }
-
- return nil
- })
- })
-
- return oldUsers, err
-}
-
-func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
- list := []*users.User{}
-
- for _, oldUser := range old {
- user := &users.User{
- Username: oldUser.Username,
- Password: oldUser.Password,
- Scope: oldUser.Scope,
- Locale: oldUser.Locale,
- LockPassword: oldUser.LockPassword,
- ViewMode: users.ViewMode(oldUser.ViewMode),
- Commands: oldUser.Commands,
- Rules: []rules.Rule{},
- Perm: users.Permissions{
- Admin: oldUser.Admin,
- Execute: oldUser.AllowCommands,
- Create: oldUser.AllowNew,
- Rename: oldUser.AllowEdit,
- Modify: oldUser.AllowEdit,
- Delete: oldUser.AllowEdit,
- Share: true,
- Download: true,
- },
- }
-
- for _, rule := range oldUser.Rules {
- user.Rules = append(user.Rules, *rule)
- }
-
- err := user.Clean("")
- if err != nil {
- return nil, err
- }
-
- list = append(list, user)
- }
-
- return list, nil
-}
-
-func importUsers(old *storm.DB, sto *storage.Storage) error {
- oldUsers, err := readOldUsers(old)
- if err != nil {
- return err
- }
-
- newUsers, err := convertUsersToNew(oldUsers)
- if err != nil {
- return err
- }
-
- for _, user := range newUsers {
- err = sto.Users.Save(user)
- if err != nil {
- return err
- }
- }
-
- fmt.Printf("%d users successfully imported into the new DB.\n", len(newUsers))
- return nil
-}
From c4c1cea2302605b353fecd913edadaa86abe5573 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 09:01:54 +0100
Subject: [PATCH 017/120] docs: remove partially incorrect env variables info
---
www/docs/configuration.md | 6 ------
1 file changed, 6 deletions(-)
diff --git a/www/docs/configuration.md b/www/docs/configuration.md
index 157a54e8..77f341a4 100644
--- a/www/docs/configuration.md
+++ b/www/docs/configuration.md
@@ -2,12 +2,6 @@
Most of the configuration can be understood through the command line interface documentation. To access it, you need to install File Browser and run `filebrowser --help`. In this page, we cover some specific, more complex, topics.
-## Flags as Environment Variables
-
-In some situations, it is easier to use environment variables instead of flags. For example, if you're using our provided Docker image, it's easier for you to use environment variables to customize the settings instead of flags.
-
-All flags should be available as environment variables prefixed with `FB_`. For example, the flag `--disable-thumbnails` is available as `FB_DISABLE_THUMBNAILS`.
-
## Custom Branding
You can customize File Browser to use your own branding. This includes the following:
From 2d9689dd6a92789cfefd12e09e87cccc14d87824 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 10:14:59 +0100
Subject: [PATCH 018/120] docs: add CLI usage and integrate generation in
release
---
.github/workflows/ci.yaml | 2 +-
CONTRIBUTING.md | 2 +-
Taskfile.yml | 34 ++--
cmd/docs.go | 158 +++++-------------
go.mod | 2 +
go.sum | 2 +
www/docs/cli/filebrowser-cmds-add.md | 29 ++++
www/docs/cli/filebrowser-cmds-ls.md | 30 ++++
www/docs/cli/filebrowser-cmds-rm.md | 37 ++++
www/docs/cli/filebrowser-cmds.md | 28 ++++
www/docs/cli/filebrowser-completion-bash.md | 50 ++++++
www/docs/cli/filebrowser-completion-fish.md | 41 +++++
.../cli/filebrowser-completion-powershell.md | 38 +++++
www/docs/cli/filebrowser-completion-zsh.md | 52 ++++++
www/docs/cli/filebrowser-completion.md | 31 ++++
www/docs/cli/filebrowser-config-cat.md | 29 ++++
www/docs/cli/filebrowser-config-export.md | 31 ++++
www/docs/cli/filebrowser-config-import.md | 36 ++++
www/docs/cli/filebrowser-config-init.md | 87 ++++++++++
www/docs/cli/filebrowser-config-set.md | 84 ++++++++++
www/docs/cli/filebrowser-config.md | 30 ++++
www/docs/cli/filebrowser-hash.md | 29 ++++
www/docs/cli/filebrowser-rules-add.md | 33 ++++
www/docs/cli/filebrowser-rules-ls.md | 31 ++++
www/docs/cli/filebrowser-rules-rm.md | 40 +++++
www/docs/cli/filebrowser-rules.md | 34 ++++
www/docs/cli/filebrowser-users-add.md | 48 ++++++
www/docs/cli/filebrowser-users-export.md | 30 ++++
www/docs/cli/filebrowser-users-find.md | 29 ++++
www/docs/cli/filebrowser-users-import.md | 34 ++++
www/docs/cli/filebrowser-users-ls.md | 25 +++
www/docs/cli/filebrowser-users-rm.md | 29 ++++
www/docs/cli/filebrowser-users-update.md | 51 ++++++
www/docs/cli/filebrowser-users.md | 32 ++++
www/docs/cli/filebrowser-version.md | 25 +++
www/docs/cli/filebrowser.md | 83 +++++++++
www/mkdocs.yml | 36 +++-
37 files changed, 1289 insertions(+), 133 deletions(-)
create mode 100644 www/docs/cli/filebrowser-cmds-add.md
create mode 100644 www/docs/cli/filebrowser-cmds-ls.md
create mode 100644 www/docs/cli/filebrowser-cmds-rm.md
create mode 100644 www/docs/cli/filebrowser-cmds.md
create mode 100644 www/docs/cli/filebrowser-completion-bash.md
create mode 100644 www/docs/cli/filebrowser-completion-fish.md
create mode 100644 www/docs/cli/filebrowser-completion-powershell.md
create mode 100644 www/docs/cli/filebrowser-completion-zsh.md
create mode 100644 www/docs/cli/filebrowser-completion.md
create mode 100644 www/docs/cli/filebrowser-config-cat.md
create mode 100644 www/docs/cli/filebrowser-config-export.md
create mode 100644 www/docs/cli/filebrowser-config-import.md
create mode 100644 www/docs/cli/filebrowser-config-init.md
create mode 100644 www/docs/cli/filebrowser-config-set.md
create mode 100644 www/docs/cli/filebrowser-config.md
create mode 100644 www/docs/cli/filebrowser-hash.md
create mode 100644 www/docs/cli/filebrowser-rules-add.md
create mode 100644 www/docs/cli/filebrowser-rules-ls.md
create mode 100644 www/docs/cli/filebrowser-rules-rm.md
create mode 100644 www/docs/cli/filebrowser-rules.md
create mode 100644 www/docs/cli/filebrowser-users-add.md
create mode 100644 www/docs/cli/filebrowser-users-export.md
create mode 100644 www/docs/cli/filebrowser-users-find.md
create mode 100644 www/docs/cli/filebrowser-users-import.md
create mode 100644 www/docs/cli/filebrowser-users-ls.md
create mode 100644 www/docs/cli/filebrowser-users-rm.md
create mode 100644 www/docs/cli/filebrowser-users-update.md
create mode 100644 www/docs/cli/filebrowser-users.md
create mode 100644 www/docs/cli/filebrowser-version.md
create mode 100644 www/docs/cli/filebrowser.md
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 0f222ecd..b389be5f 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -97,7 +97,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Install Task
uses: go-task/setup-task@v1
- - run: task build-frontend
+ - run: task build:frontend
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d6e694f1..311a2fd7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -86,7 +86,7 @@ task docs
To start a local server on port `8000` to view the built documentation:
```bash
-task docs-serve
+task docs:serve
```
## Release
diff --git a/Taskfile.yml b/Taskfile.yml
index 9721317f..855507bc 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -10,14 +10,14 @@ vars:
-v ./CONTRIBUTING.md:/docs/docs/contributing.md
tasks:
- build-frontend:
+ build:frontend:
desc: Build frontend assets
dir: frontend
cmds:
- pnpm install --frozen-lockfile
- pnpm run build
- build-backend:
+ build:backend:
desc: Build backend binary
cmds:
- go build -ldflags='-s -w -X "github.com/filebrowser/filebrowser/v2/version.Version={{.VERSION}}" -X "github.com/filebrowser/filebrowser/v2/version.CommitSHA={{.GIT_COMMIT}}"' -o filebrowser .
@@ -30,16 +30,16 @@ tasks:
build:
desc: Build both frontend and backend
cmds:
- - task: build-frontend
- - task: build-backend
+ - task: build:frontend
+ - task: build:backend
- release-make:
+ release:make:
internal: true
prompt: Do you wish to proceed?
cmds:
- pnpm dlx commit-and-tag-version -s
- release-dry-run:
+ release:dry-run:
internal: true
cmds:
- pnpm dlx commit-and-tag-version --dry-run --skip
@@ -47,10 +47,20 @@ tasks:
release:
desc: Create a new release
cmds:
- - task: release-dry-run
- - task: release-make
+ - task: docs:cli:generate
+ - git add www/docs/cli
+ - task: release:dry-run
+ - task: release:make
- docs-image-make:
+ docs:cli:generate:
+ cmds:
+ - rm -rf www/docs/cli
+ - mkdir -p www/docs/cli
+ - go run . docs
+ generates:
+ - www/docs/cli
+
+ docs:docker:generate:
internal: true
cmds:
- docker build -f www/Dockerfile --progress=plain -t filebrowser.site www
@@ -59,11 +69,11 @@ tasks:
desc: Generate documentation
cmds:
- rm -rf www/public
- - task: docs-image-make
+ - task: docs:docker:generate
- docker run --rm {{.SITE_DOCKER_FLAGS}} filebrowser.site build -d "public"
- docs-serve:
+ docs:serve:
desc: Serve documentation
cmds:
- - task: docs-image-make
+ - task: docs:docker:generate
- docker run --rm -it -p 8000:8000 {{.SITE_DOCKER_FLAGS}} filebrowser.site
diff --git a/cmd/docs.go b/cmd/docs.go
index 90e5a259..7f4f536e 100644
--- a/cmd/docs.go
+++ b/cmd/docs.go
@@ -3,36 +3,18 @@ package cmd
import (
"bytes"
"fmt"
- "io"
"os"
- "path/filepath"
- "sort"
+ "path"
+ "regexp"
"strings"
"github.com/spf13/cobra"
- "github.com/spf13/pflag"
+ "github.com/spf13/cobra/doc"
)
func init() {
rootCmd.AddCommand(docsCmd)
- docsCmd.Flags().StringP("path", "p", "./docs", "path to save the docs")
-}
-
-func printToc(names []string) {
- for i, name := range names {
- name = strings.TrimSuffix(name, filepath.Ext(name))
- name = strings.ReplaceAll(name, "-", " ")
- names[i] = name
- }
-
- sort.Strings(names)
-
- toc := ""
- for _, name := range names {
- toc += "* [" + name + "](cli/" + strings.ReplaceAll(name, " ", "-") + ".md)\n"
- }
-
- fmt.Println(toc)
+ docsCmd.Flags().String("out", "www/docs/cli", "directory to write the docs to")
}
var docsCmd = &cobra.Command{
@@ -40,115 +22,61 @@ var docsCmd = &cobra.Command{
Hidden: true,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
- dir, err := getString(cmd.Flags(), "path")
+ outputDir, err := cmd.Flags().GetString("out")
if err != nil {
return err
}
- err = generateDocs(rootCmd, dir)
+ tempDir, err := os.MkdirTemp(os.TempDir(), "filebrowser-docs-")
if err != nil {
return err
}
- names := []string{}
+ defer os.RemoveAll(tempDir)
- err = filepath.Walk(dir, func(_ string, info os.FileInfo, err error) error {
- if err != nil || info.IsDir() {
- return err
- }
+ rootCmd.Root().DisableAutoGenTag = true
- if !strings.HasPrefix(info.Name(), "filebrowser") {
- return nil
- }
-
- names = append(names, info.Name())
- return nil
+ err = doc.GenMarkdownTreeCustom(cmd.Root(), tempDir, func(f string) string {
+ return ""
+ }, func(s string) string {
+ return s
})
if err != nil {
return err
}
- printToc(names)
- return nil
- },
-}
-
-func generateDocs(cmd *cobra.Command, dir string) error {
- for _, c := range cmd.Commands() {
- if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
- continue
- }
-
- err := generateDocs(c, dir)
+ entries, err := os.ReadDir(tempDir)
if err != nil {
return err
}
- }
- basename := strings.ReplaceAll(cmd.CommandPath(), " ", "-") + ".md"
- filename := filepath.Join(dir, basename)
- f, err := os.Create(filename)
- if err != nil {
- return err
- }
- defer f.Close()
- return generateMarkdown(cmd, f)
-}
-
-func generateMarkdown(cmd *cobra.Command, w io.Writer) error {
- cmd.InitDefaultHelpCmd()
- cmd.InitDefaultHelpFlag()
-
- buf := new(bytes.Buffer)
- name := cmd.CommandPath()
-
- short := cmd.Short
- long := cmd.Long
- if long == "" {
- long = short
- }
-
- buf.WriteString("---\ndescription: " + short + "\n---\n\n")
- buf.WriteString("# " + name + "\n\n")
- buf.WriteString("## Synopsis\n\n")
- buf.WriteString(long + "\n\n")
-
- if cmd.Runnable() {
- _, _ = fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.UseLine())
- }
-
- if cmd.Example != "" {
- buf.WriteString("## Examples\n\n")
- _, _ = fmt.Fprintf(buf, "```\n%s\n```\n\n", cmd.Example)
- }
-
- printOptions(buf, cmd)
- _, err := buf.WriteTo(w)
- return err
-}
-
-func generateFlagsTable(fs *pflag.FlagSet, buf io.StringWriter) {
- _, _ = buf.WriteString("| Name | Shorthand | Usage |\n")
- _, _ = buf.WriteString("|------|-----------|-------|\n")
-
- fs.VisitAll(func(f *pflag.Flag) {
- _, _ = buf.WriteString("|" + f.Name + "|" + f.Shorthand + "|" + f.Usage + "|\n")
- })
-}
-
-func printOptions(buf *bytes.Buffer, cmd *cobra.Command) {
- flags := cmd.NonInheritedFlags()
- flags.SetOutput(buf)
- if flags.HasAvailableFlags() {
- buf.WriteString("## Options\n\n")
- generateFlagsTable(flags, buf)
- buf.WriteString("\n")
- }
-
- parentFlags := cmd.InheritedFlags()
- parentFlags.SetOutput(buf)
- if parentFlags.HasAvailableFlags() {
- buf.WriteString("### Inherited\n\n")
- generateFlagsTable(parentFlags, buf)
- buf.WriteString("\n")
- }
+ headerRegex := regexp.MustCompile(`(?m)^(##)(.*)$`)
+ linkRegex := regexp.MustCompile(`\(filebrowser(.*)\.md\)`)
+
+ fmt.Println("Generated Documents:")
+
+ for _, entry := range entries {
+ srcPath := path.Join(tempDir, entry.Name())
+ dstPath := path.Join(outputDir, strings.ReplaceAll(entry.Name(), "_", "-"))
+
+ data, err := os.ReadFile(srcPath)
+ if err != nil {
+ return err
+ }
+
+ data = headerRegex.ReplaceAll(data, []byte("#$2"))
+ data = linkRegex.ReplaceAllFunc(data, func(b []byte) []byte {
+ return bytes.ReplaceAll(b, []byte("_"), []byte("-"))
+ })
+ data = bytes.ReplaceAll(data, []byte("## SEE ALSO"), []byte("## See Also"))
+
+ err = os.WriteFile(dstPath, data, 0666)
+ if err != nil {
+ return err
+ }
+
+ fmt.Println("- " + dstPath)
+ }
+
+ return nil
+ },
}
diff --git a/go.mod b/go.mod
index 724b0c8f..47da2619 100644
--- a/go.mod
+++ b/go.mod
@@ -38,6 +38,7 @@ require (
github.com/bodgit/plumbing v1.3.0 // indirect
github.com/bodgit/sevenzip v1.6.1 // indirect
github.com/bodgit/windows v1.0.1 // indirect
+ github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dsnet/compress v0.0.2-0.20230904184137-39efe44ab707 // indirect
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
@@ -60,6 +61,7 @@ require (
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/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sorairolake/lzip-go v0.3.8 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
diff --git a/go.sum b/go.sum
index 0b374007..c6b0e41b 100644
--- a/go.sum
+++ b/go.sum
@@ -47,6 +47,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
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 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
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=
@@ -196,6 +197,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
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.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
diff --git a/www/docs/cli/filebrowser-cmds-add.md b/www/docs/cli/filebrowser-cmds-add.md
new file mode 100644
index 00000000..fc064ea9
--- /dev/null
+++ b/www/docs/cli/filebrowser-cmds-add.md
@@ -0,0 +1,29 @@
+# filebrowser cmds add
+
+Add a command to run on a specific event
+
+## Synopsis
+
+Add a command to run on a specific event.
+
+```
+filebrowser cmds add [flags]
+```
+
+## Options
+
+```
+ -h, --help help for add
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility
+
diff --git a/www/docs/cli/filebrowser-cmds-ls.md b/www/docs/cli/filebrowser-cmds-ls.md
new file mode 100644
index 00000000..136df2e8
--- /dev/null
+++ b/www/docs/cli/filebrowser-cmds-ls.md
@@ -0,0 +1,30 @@
+# filebrowser cmds ls
+
+List all commands for each event
+
+## Synopsis
+
+List all commands for each event.
+
+```
+filebrowser cmds ls [flags]
+```
+
+## Options
+
+```
+ -e, --event string event name, without 'before' or 'after'
+ -h, --help help for ls
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility
+
diff --git a/www/docs/cli/filebrowser-cmds-rm.md b/www/docs/cli/filebrowser-cmds-rm.md
new file mode 100644
index 00000000..837813b9
--- /dev/null
+++ b/www/docs/cli/filebrowser-cmds-rm.md
@@ -0,0 +1,37 @@
+# filebrowser cmds rm
+
+Removes a command from an event hooker
+
+## Synopsis
+
+Removes a command from an event hooker. The provided index
+is the same that's printed when you run 'cmds ls'. Note
+that after each removal/addition, the index of the
+commands change. So be careful when removing them after each
+other.
+
+You can also specify an optional parameter (index_end) so
+you can remove all commands from 'index' to 'index_end',
+including 'index_end'.
+
+```
+filebrowser cmds rm [index_end] [flags]
+```
+
+## Options
+
+```
+ -h, --help help for rm
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility
+
diff --git a/www/docs/cli/filebrowser-cmds.md b/www/docs/cli/filebrowser-cmds.md
new file mode 100644
index 00000000..bc61418b
--- /dev/null
+++ b/www/docs/cli/filebrowser-cmds.md
@@ -0,0 +1,28 @@
+# filebrowser cmds
+
+Command runner management utility
+
+## Synopsis
+
+Command runner management utility.
+
+## Options
+
+```
+ -h, --help help for cmds
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+* [filebrowser cmds add](filebrowser-cmds-add.md) - Add a command to run on a specific event
+* [filebrowser cmds ls](filebrowser-cmds-ls.md) - List all commands for each event
+* [filebrowser cmds rm](filebrowser-cmds-rm.md) - Removes a command from an event hooker
+
diff --git a/www/docs/cli/filebrowser-completion-bash.md b/www/docs/cli/filebrowser-completion-bash.md
new file mode 100644
index 00000000..e4c8963a
--- /dev/null
+++ b/www/docs/cli/filebrowser-completion-bash.md
@@ -0,0 +1,50 @@
+# filebrowser completion bash
+
+Generate the autocompletion script for bash
+
+## Synopsis
+
+Generate the autocompletion script for the bash shell.
+
+This script depends on the 'bash-completion' package.
+If it is not installed already, you can install it via your OS's package manager.
+
+To load completions in your current shell session:
+
+ source <(filebrowser completion bash)
+
+To load completions for every new session, execute once:
+
+### Linux:
+
+ filebrowser completion bash > /etc/bash_completion.d/filebrowser
+
+### macOS:
+
+ filebrowser completion bash > $(brew --prefix)/etc/bash_completion.d/filebrowser
+
+You will need to start a new shell for this setup to take effect.
+
+
+```
+filebrowser completion bash
+```
+
+## Options
+
+```
+ -h, --help help for bash
+ --no-descriptions disable completion descriptions
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell
+
diff --git a/www/docs/cli/filebrowser-completion-fish.md b/www/docs/cli/filebrowser-completion-fish.md
new file mode 100644
index 00000000..e8297aa1
--- /dev/null
+++ b/www/docs/cli/filebrowser-completion-fish.md
@@ -0,0 +1,41 @@
+# filebrowser completion fish
+
+Generate the autocompletion script for fish
+
+## Synopsis
+
+Generate the autocompletion script for the fish shell.
+
+To load completions in your current shell session:
+
+ filebrowser completion fish | source
+
+To load completions for every new session, execute once:
+
+ filebrowser completion fish > ~/.config/fish/completions/filebrowser.fish
+
+You will need to start a new shell for this setup to take effect.
+
+
+```
+filebrowser completion fish [flags]
+```
+
+## Options
+
+```
+ -h, --help help for fish
+ --no-descriptions disable completion descriptions
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell
+
diff --git a/www/docs/cli/filebrowser-completion-powershell.md b/www/docs/cli/filebrowser-completion-powershell.md
new file mode 100644
index 00000000..21f84c4c
--- /dev/null
+++ b/www/docs/cli/filebrowser-completion-powershell.md
@@ -0,0 +1,38 @@
+# filebrowser completion powershell
+
+Generate the autocompletion script for powershell
+
+## Synopsis
+
+Generate the autocompletion script for powershell.
+
+To load completions in your current shell session:
+
+ filebrowser completion powershell | Out-String | Invoke-Expression
+
+To load completions for every new session, add the output of the above command
+to your powershell profile.
+
+
+```
+filebrowser completion powershell [flags]
+```
+
+## Options
+
+```
+ -h, --help help for powershell
+ --no-descriptions disable completion descriptions
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell
+
diff --git a/www/docs/cli/filebrowser-completion-zsh.md b/www/docs/cli/filebrowser-completion-zsh.md
new file mode 100644
index 00000000..f54794b0
--- /dev/null
+++ b/www/docs/cli/filebrowser-completion-zsh.md
@@ -0,0 +1,52 @@
+# filebrowser completion zsh
+
+Generate the autocompletion script for zsh
+
+## Synopsis
+
+Generate the autocompletion script for the zsh shell.
+
+If shell completion is not already enabled in your environment you will need
+to enable it. You can execute the following once:
+
+ echo "autoload -U compinit; compinit" >> ~/.zshrc
+
+To load completions in your current shell session:
+
+ source <(filebrowser completion zsh)
+
+To load completions for every new session, execute once:
+
+### Linux:
+
+ filebrowser completion zsh > "${fpath[1]}/_filebrowser"
+
+### macOS:
+
+ filebrowser completion zsh > $(brew --prefix)/share/zsh/site-functions/_filebrowser
+
+You will need to start a new shell for this setup to take effect.
+
+
+```
+filebrowser completion zsh [flags]
+```
+
+## Options
+
+```
+ -h, --help help for zsh
+ --no-descriptions disable completion descriptions
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell
+
diff --git a/www/docs/cli/filebrowser-completion.md b/www/docs/cli/filebrowser-completion.md
new file mode 100644
index 00000000..b2c6bdc1
--- /dev/null
+++ b/www/docs/cli/filebrowser-completion.md
@@ -0,0 +1,31 @@
+# filebrowser completion
+
+Generate the autocompletion script for the specified shell
+
+## Synopsis
+
+Generate the autocompletion script for filebrowser for the specified shell.
+See each sub-command's help for details on how to use the generated script.
+
+
+## Options
+
+```
+ -h, --help help for completion
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+* [filebrowser completion bash](filebrowser-completion-bash.md) - Generate the autocompletion script for bash
+* [filebrowser completion fish](filebrowser-completion-fish.md) - Generate the autocompletion script for fish
+* [filebrowser completion powershell](filebrowser-completion-powershell.md) - Generate the autocompletion script for powershell
+* [filebrowser completion zsh](filebrowser-completion-zsh.md) - Generate the autocompletion script for zsh
+
diff --git a/www/docs/cli/filebrowser-config-cat.md b/www/docs/cli/filebrowser-config-cat.md
new file mode 100644
index 00000000..952580fd
--- /dev/null
+++ b/www/docs/cli/filebrowser-config-cat.md
@@ -0,0 +1,29 @@
+# filebrowser config cat
+
+Prints the configuration
+
+## Synopsis
+
+Prints the configuration.
+
+```
+filebrowser config cat [flags]
+```
+
+## Options
+
+```
+ -h, --help help for cat
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser config](filebrowser-config.md) - Configuration management utility
+
diff --git a/www/docs/cli/filebrowser-config-export.md b/www/docs/cli/filebrowser-config-export.md
new file mode 100644
index 00000000..141d4e8e
--- /dev/null
+++ b/www/docs/cli/filebrowser-config-export.md
@@ -0,0 +1,31 @@
+# filebrowser config export
+
+Export the configuration to a file
+
+## Synopsis
+
+Export the configuration to a file. The path must be for a
+json or yaml file. This exported configuration can be changed,
+and imported again with 'config import' command.
+
+```
+filebrowser config export [flags]
+```
+
+## Options
+
+```
+ -h, --help help for export
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser config](filebrowser-config.md) - Configuration management utility
+
diff --git a/www/docs/cli/filebrowser-config-import.md b/www/docs/cli/filebrowser-config-import.md
new file mode 100644
index 00000000..871da341
--- /dev/null
+++ b/www/docs/cli/filebrowser-config-import.md
@@ -0,0 +1,36 @@
+# filebrowser config import
+
+Import a configuration file
+
+## Synopsis
+
+Import a configuration file. This will replace all the existing
+configuration. Can be used with or without unexisting databases.
+
+If used with a nonexisting database, a key will be generated
+automatically. Otherwise the key will be kept the same as in the
+database.
+
+The path must be for a json or yaml file.
+
+```
+filebrowser config import [flags]
+```
+
+## Options
+
+```
+ -h, --help help for import
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser config](filebrowser-config.md) - Configuration management utility
+
diff --git a/www/docs/cli/filebrowser-config-init.md b/www/docs/cli/filebrowser-config-init.md
new file mode 100644
index 00000000..f317c9a0
--- /dev/null
+++ b/www/docs/cli/filebrowser-config-init.md
@@ -0,0 +1,87 @@
+# filebrowser config init
+
+Initialize a new database
+
+## Synopsis
+
+Initialize a new database to use with File Browser. All of
+this options can be changed in the future with the command
+'filebrowser config set'. The user related flags apply
+to the defaults when creating new users and you don't
+override the options.
+
+```
+filebrowser config init [flags]
+```
+
+## Options
+
+```
+ --aceEditorTheme string ace editor's syntax highlighting theme for users
+ -a, --address string address to listen on (default "127.0.0.1")
+ --auth.command string command for auth.method=hook
+ --auth.header string HTTP header for auth.method=proxy
+ --auth.method string authentication type (default "json")
+ -b, --baseurl string base url
+ --branding.color string set the theme color
+ --branding.disableExternal disable external links such as GitHub links
+ --branding.disableUsedPercentage disable used disk percentage graph
+ --branding.files string path to directory with images and custom styles
+ --branding.name string replace 'File Browser' by this name
+ --branding.theme string set the theme
+ --cache-dir string file cache directory (disabled if empty)
+ -t, --cert string tls certificate
+ --commands strings a list of the commands a user can execute
+ --create-user-dir generate user's home directory automatically
+ --dateFormat use date format (true for absolute time, false for relative)
+ --dir-mode string Mode bits that new directories are created with (default "0o750")
+ --disable-exec disables Command Runner feature (default true)
+ --disable-preview-resize disable resize of image previews
+ --disable-thumbnails disable image thumbnails
+ --disable-type-detection-by-header disables type detection by reading file headers
+ --file-mode string Mode bits that new files are created with (default "0o640")
+ -h, --help help for init
+ --hide-login-button hide login button from public pages
+ --hideDotfiles hide dotfiles
+ --img-processors int image processors count (default 4)
+ -k, --key string tls key
+ --locale string locale for users (default "en")
+ --lockPassword lock password
+ -l, --log string log output (default "stdout")
+ --minimum-password-length uint minimum password length for new users (default 12)
+ --perm.admin admin perm for users
+ --perm.create create perm for users (default true)
+ --perm.delete delete perm for users (default true)
+ --perm.download download perm for users (default true)
+ --perm.execute execute perm for users (default true)
+ --perm.modify modify perm for users (default true)
+ --perm.rename rename perm for users (default true)
+ --perm.share share perm for users (default true)
+ -p, --port string port to listen on (default "8080")
+ --recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
+ --recaptcha.key string ReCaptcha site key
+ --recaptcha.secret string ReCaptcha secret
+ -r, --root string root to prepend to relative paths (default ".")
+ --scope string scope for users (default ".")
+ --shell string shell command to which other commands should be appended
+ -s, --signup allow users to signup
+ --singleClick use single clicks only
+ --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
+ --socket-perm uint32 unix socket file permissions (default 438)
+ --sorting.asc sorting by ascending order
+ --sorting.by string sorting mode (name, size or modified) (default "name")
+ --token-expiration-time string user session timeout (default "2h")
+ --viewMode string view mode for users (default "list")
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser config](filebrowser-config.md) - Configuration management utility
+
diff --git a/www/docs/cli/filebrowser-config-set.md b/www/docs/cli/filebrowser-config-set.md
new file mode 100644
index 00000000..a396ab13
--- /dev/null
+++ b/www/docs/cli/filebrowser-config-set.md
@@ -0,0 +1,84 @@
+# filebrowser config set
+
+Updates the configuration
+
+## Synopsis
+
+Updates the configuration. Set the flags for the options
+you want to change. Other options will remain unchanged.
+
+```
+filebrowser config set [flags]
+```
+
+## Options
+
+```
+ --aceEditorTheme string ace editor's syntax highlighting theme for users
+ -a, --address string address to listen on (default "127.0.0.1")
+ --auth.command string command for auth.method=hook
+ --auth.header string HTTP header for auth.method=proxy
+ --auth.method string authentication type (default "json")
+ -b, --baseurl string base url
+ --branding.color string set the theme color
+ --branding.disableExternal disable external links such as GitHub links
+ --branding.disableUsedPercentage disable used disk percentage graph
+ --branding.files string path to directory with images and custom styles
+ --branding.name string replace 'File Browser' by this name
+ --branding.theme string set the theme
+ --cache-dir string file cache directory (disabled if empty)
+ -t, --cert string tls certificate
+ --commands strings a list of the commands a user can execute
+ --create-user-dir generate user's home directory automatically
+ --dateFormat use date format (true for absolute time, false for relative)
+ --dir-mode string Mode bits that new directories are created with (default "0o750")
+ --disable-exec disables Command Runner feature (default true)
+ --disable-preview-resize disable resize of image previews
+ --disable-thumbnails disable image thumbnails
+ --disable-type-detection-by-header disables type detection by reading file headers
+ --file-mode string Mode bits that new files are created with (default "0o640")
+ -h, --help help for set
+ --hide-login-button hide login button from public pages
+ --hideDotfiles hide dotfiles
+ --img-processors int image processors count (default 4)
+ -k, --key string tls key
+ --locale string locale for users (default "en")
+ --lockPassword lock password
+ -l, --log string log output (default "stdout")
+ --minimum-password-length uint minimum password length for new users (default 12)
+ --perm.admin admin perm for users
+ --perm.create create perm for users (default true)
+ --perm.delete delete perm for users (default true)
+ --perm.download download perm for users (default true)
+ --perm.execute execute perm for users (default true)
+ --perm.modify modify perm for users (default true)
+ --perm.rename rename perm for users (default true)
+ --perm.share share perm for users (default true)
+ -p, --port string port to listen on (default "8080")
+ --recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
+ --recaptcha.key string ReCaptcha site key
+ --recaptcha.secret string ReCaptcha secret
+ -r, --root string root to prepend to relative paths (default ".")
+ --scope string scope for users (default ".")
+ --shell string shell command to which other commands should be appended
+ -s, --signup allow users to signup
+ --singleClick use single clicks only
+ --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
+ --socket-perm uint32 unix socket file permissions (default 438)
+ --sorting.asc sorting by ascending order
+ --sorting.by string sorting mode (name, size or modified) (default "name")
+ --token-expiration-time string user session timeout (default "2h")
+ --viewMode string view mode for users (default "list")
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser config](filebrowser-config.md) - Configuration management utility
+
diff --git a/www/docs/cli/filebrowser-config.md b/www/docs/cli/filebrowser-config.md
new file mode 100644
index 00000000..b87dbf07
--- /dev/null
+++ b/www/docs/cli/filebrowser-config.md
@@ -0,0 +1,30 @@
+# filebrowser config
+
+Configuration management utility
+
+## Synopsis
+
+Configuration management utility.
+
+## Options
+
+```
+ -h, --help help for config
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+* [filebrowser config cat](filebrowser-config-cat.md) - Prints the configuration
+* [filebrowser config export](filebrowser-config-export.md) - Export the configuration to a file
+* [filebrowser config import](filebrowser-config-import.md) - Import a configuration file
+* [filebrowser config init](filebrowser-config-init.md) - Initialize a new database
+* [filebrowser config set](filebrowser-config-set.md) - Updates the configuration
+
diff --git a/www/docs/cli/filebrowser-hash.md b/www/docs/cli/filebrowser-hash.md
new file mode 100644
index 00000000..9d480547
--- /dev/null
+++ b/www/docs/cli/filebrowser-hash.md
@@ -0,0 +1,29 @@
+# filebrowser hash
+
+Hashes a password
+
+## Synopsis
+
+Hashes a password using bcrypt algorithm.
+
+```
+filebrowser hash [flags]
+```
+
+## Options
+
+```
+ -h, --help help for hash
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+
diff --git a/www/docs/cli/filebrowser-rules-add.md b/www/docs/cli/filebrowser-rules-add.md
new file mode 100644
index 00000000..2fd2efaf
--- /dev/null
+++ b/www/docs/cli/filebrowser-rules-add.md
@@ -0,0 +1,33 @@
+# filebrowser rules add
+
+Add a global rule or user rule
+
+## Synopsis
+
+Add a global rule or user rule.
+
+```
+filebrowser rules add [flags]
+```
+
+## Options
+
+```
+ -a, --allow indicates this is an allow rule
+ -h, --help help for add
+ -r, --regex indicates this is a regex rule
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+ -i, --id uint id of user to which the rules apply
+ -u, --username string username of user to which the rules apply
+```
+
+## See Also
+
+* [filebrowser rules](filebrowser-rules.md) - Rules management utility
+
diff --git a/www/docs/cli/filebrowser-rules-ls.md b/www/docs/cli/filebrowser-rules-ls.md
new file mode 100644
index 00000000..8a9cc6eb
--- /dev/null
+++ b/www/docs/cli/filebrowser-rules-ls.md
@@ -0,0 +1,31 @@
+# filebrowser rules ls
+
+List global rules or user specific rules
+
+## Synopsis
+
+List global rules or user specific rules.
+
+```
+filebrowser rules ls [flags]
+```
+
+## Options
+
+```
+ -h, --help help for ls
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+ -i, --id uint id of user to which the rules apply
+ -u, --username string username of user to which the rules apply
+```
+
+## See Also
+
+* [filebrowser rules](filebrowser-rules.md) - Rules management utility
+
diff --git a/www/docs/cli/filebrowser-rules-rm.md b/www/docs/cli/filebrowser-rules-rm.md
new file mode 100644
index 00000000..1870afbb
--- /dev/null
+++ b/www/docs/cli/filebrowser-rules-rm.md
@@ -0,0 +1,40 @@
+# filebrowser rules rm
+
+Remove a global rule or user rule
+
+## Synopsis
+
+Remove a global rule or user rule. The provided index
+is the same that's printed when you run 'rules ls'. Note
+that after each removal/addition, the index of the
+commands change. So be careful when removing them after each
+other.
+
+You can also specify an optional parameter (index_end) so
+you can remove all commands from 'index' to 'index_end',
+including 'index_end'.
+
+```
+filebrowser rules rm [index_end] [flags]
+```
+
+## Options
+
+```
+ -h, --help help for rm
+ --index uint index of rule to remove
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+ -i, --id uint id of user to which the rules apply
+ -u, --username string username of user to which the rules apply
+```
+
+## See Also
+
+* [filebrowser rules](filebrowser-rules.md) - Rules management utility
+
diff --git a/www/docs/cli/filebrowser-rules.md b/www/docs/cli/filebrowser-rules.md
new file mode 100644
index 00000000..cc8386d0
--- /dev/null
+++ b/www/docs/cli/filebrowser-rules.md
@@ -0,0 +1,34 @@
+# filebrowser rules
+
+Rules management utility
+
+## Synopsis
+
+On each subcommand you'll have available at least two flags:
+"username" and "id". You must either set only one of them
+or none. If you set one of them, the command will apply to
+an user, otherwise it will be applied to the global set or
+rules.
+
+## Options
+
+```
+ -h, --help help for rules
+ -i, --id uint id of user to which the rules apply
+ -u, --username string username of user to which the rules apply
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+* [filebrowser rules add](filebrowser-rules-add.md) - Add a global rule or user rule
+* [filebrowser rules ls](filebrowser-rules-ls.md) - List global rules or user specific rules
+* [filebrowser rules rm](filebrowser-rules-rm.md) - Remove a global rule or user rule
+
diff --git a/www/docs/cli/filebrowser-users-add.md b/www/docs/cli/filebrowser-users-add.md
new file mode 100644
index 00000000..c6c5b53d
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-add.md
@@ -0,0 +1,48 @@
+# filebrowser users add
+
+Create a new user
+
+## Synopsis
+
+Create a new user and add it to the database.
+
+```
+filebrowser users add [flags]
+```
+
+## Options
+
+```
+ --aceEditorTheme string ace editor's syntax highlighting theme for users
+ --commands strings a list of the commands a user can execute
+ --dateFormat use date format (true for absolute time, false for relative)
+ -h, --help help for add
+ --hideDotfiles hide dotfiles
+ --locale string locale for users (default "en")
+ --lockPassword lock password
+ --perm.admin admin perm for users
+ --perm.create create perm for users (default true)
+ --perm.delete delete perm for users (default true)
+ --perm.download download perm for users (default true)
+ --perm.execute execute perm for users (default true)
+ --perm.modify modify perm for users (default true)
+ --perm.rename rename perm for users (default true)
+ --perm.share share perm for users (default true)
+ --scope string scope for users (default ".")
+ --singleClick use single clicks only
+ --sorting.asc sorting by ascending order
+ --sorting.by string sorting mode (name, size or modified) (default "name")
+ --viewMode string view mode for users (default "list")
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users-export.md b/www/docs/cli/filebrowser-users-export.md
new file mode 100644
index 00000000..e513a453
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-export.md
@@ -0,0 +1,30 @@
+# filebrowser users export
+
+Export all users to a file.
+
+## Synopsis
+
+Export all users to a json or yaml file. Please indicate the
+path to the file where you want to write the users.
+
+```
+filebrowser users export [flags]
+```
+
+## Options
+
+```
+ -h, --help help for export
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users-find.md b/www/docs/cli/filebrowser-users-find.md
new file mode 100644
index 00000000..19ed3924
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-find.md
@@ -0,0 +1,29 @@
+# filebrowser users find
+
+Find a user by username or id
+
+## Synopsis
+
+Find a user by username or id. If no flag is set, all users will be printed.
+
+```
+filebrowser users find [flags]
+```
+
+## Options
+
+```
+ -h, --help help for find
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users-import.md b/www/docs/cli/filebrowser-users-import.md
new file mode 100644
index 00000000..efc185fc
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-import.md
@@ -0,0 +1,34 @@
+# filebrowser users import
+
+Import users from a file
+
+## Synopsis
+
+Import users from a file. The path must be for a json or yaml
+file. You can use this command to import new users to your
+installation. For that, just don't place their ID on the files
+list or set it to 0.
+
+```
+filebrowser users import [flags]
+```
+
+## Options
+
+```
+ -h, --help help for import
+ --overwrite overwrite users with the same id/username combo
+ --replace replace the entire user base
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users-ls.md b/www/docs/cli/filebrowser-users-ls.md
new file mode 100644
index 00000000..59a4f8fe
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-ls.md
@@ -0,0 +1,25 @@
+# filebrowser users ls
+
+List all users.
+
+```
+filebrowser users ls [flags]
+```
+
+## Options
+
+```
+ -h, --help help for ls
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users-rm.md b/www/docs/cli/filebrowser-users-rm.md
new file mode 100644
index 00000000..0e3b3035
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-rm.md
@@ -0,0 +1,29 @@
+# filebrowser users rm
+
+Delete a user by username or id
+
+## Synopsis
+
+Delete a user by username or id
+
+```
+filebrowser users rm [flags]
+```
+
+## Options
+
+```
+ -h, --help help for rm
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users-update.md b/www/docs/cli/filebrowser-users-update.md
new file mode 100644
index 00000000..996bdac7
--- /dev/null
+++ b/www/docs/cli/filebrowser-users-update.md
@@ -0,0 +1,51 @@
+# filebrowser users update
+
+Updates an existing user
+
+## Synopsis
+
+Updates an existing user. Set the flags for the
+options you want to change.
+
+```
+filebrowser users update [flags]
+```
+
+## Options
+
+```
+ --aceEditorTheme string ace editor's syntax highlighting theme for users
+ --commands strings a list of the commands a user can execute
+ --dateFormat use date format (true for absolute time, false for relative)
+ -h, --help help for update
+ --hideDotfiles hide dotfiles
+ --locale string locale for users (default "en")
+ --lockPassword lock password
+ -p, --password string new password
+ --perm.admin admin perm for users
+ --perm.create create perm for users (default true)
+ --perm.delete delete perm for users (default true)
+ --perm.download download perm for users (default true)
+ --perm.execute execute perm for users (default true)
+ --perm.modify modify perm for users (default true)
+ --perm.rename rename perm for users (default true)
+ --perm.share share perm for users (default true)
+ --scope string scope for users (default ".")
+ --singleClick use single clicks only
+ --sorting.asc sorting by ascending order
+ --sorting.by string sorting mode (name, size or modified) (default "name")
+ -u, --username string new username
+ --viewMode string view mode for users (default "list")
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser users](filebrowser-users.md) - Users management utility
+
diff --git a/www/docs/cli/filebrowser-users.md b/www/docs/cli/filebrowser-users.md
new file mode 100644
index 00000000..63d82bc1
--- /dev/null
+++ b/www/docs/cli/filebrowser-users.md
@@ -0,0 +1,32 @@
+# filebrowser users
+
+Users management utility
+
+## Synopsis
+
+Users management utility.
+
+## Options
+
+```
+ -h, --help help for users
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+* [filebrowser users add](filebrowser-users-add.md) - Create a new user
+* [filebrowser users export](filebrowser-users-export.md) - Export all users to a file.
+* [filebrowser users find](filebrowser-users-find.md) - Find a user by username or id
+* [filebrowser users import](filebrowser-users-import.md) - Import users from a file
+* [filebrowser users ls](filebrowser-users-ls.md) - List all users.
+* [filebrowser users rm](filebrowser-users-rm.md) - Delete a user by username or id
+* [filebrowser users update](filebrowser-users-update.md) - Updates an existing user
+
diff --git a/www/docs/cli/filebrowser-version.md b/www/docs/cli/filebrowser-version.md
new file mode 100644
index 00000000..ec3596c5
--- /dev/null
+++ b/www/docs/cli/filebrowser-version.md
@@ -0,0 +1,25 @@
+# filebrowser version
+
+Print the version number
+
+```
+filebrowser version [flags]
+```
+
+## Options
+
+```
+ -h, --help help for version
+```
+
+## Options inherited from parent commands
+
+```
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+```
+
+## See Also
+
+* [filebrowser](filebrowser.md) - A stylish web-based file browser
+
diff --git a/www/docs/cli/filebrowser.md b/www/docs/cli/filebrowser.md
new file mode 100644
index 00000000..a8cbe669
--- /dev/null
+++ b/www/docs/cli/filebrowser.md
@@ -0,0 +1,83 @@
+# filebrowser
+
+A stylish web-based file browser
+
+## Synopsis
+
+File Browser CLI lets you create the database to use with File Browser,
+manage your users and all the configurations without accessing the
+web interface.
+
+If you've never run File Browser, you'll need to have a database for
+it. Don't worry: you don't need to setup a separate database server.
+We're using Bolt DB which is a single file database and all managed
+by ourselves.
+
+For this specific command, all the flags you have available (except
+"config" for the configuration file), can be given either through
+environment variables or configuration files.
+
+If you don't set "config", it will look for a configuration file called
+.filebrowser.{json, toml, yaml, yml} in the following directories:
+
+- ./
+- $HOME/
+- /etc/filebrowser/
+
+The precedence of the configuration values are as follows:
+
+- flags
+- environment variables
+- configuration file
+- database values
+- defaults
+
+The environment variables are prefixed by "FB_" followed by the option
+name in caps. So to set "database" via an env variable, you should
+set FB_DATABASE.
+
+Also, if the database path doesn't exist, File Browser will enter into
+the quick setup mode and a new database will be bootstrapped and a new
+user created with the credentials from options "username" and "password".
+
+```
+filebrowser [flags]
+```
+
+## Options
+
+```
+ -a, --address string address to listen on (default "127.0.0.1")
+ -b, --baseurl string base url
+ --cache-dir string file cache directory (disabled if empty)
+ -t, --cert string tls certificate
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+ --disable-exec disables Command Runner feature (default true)
+ --disable-preview-resize disable resize of image previews
+ --disable-thumbnails disable image thumbnails
+ --disable-type-detection-by-header disables type detection by reading file headers
+ -h, --help help for filebrowser
+ --img-processors int image processors count (default 4)
+ -k, --key string tls key
+ -l, --log string log output (default "stdout")
+ --noauth use the noauth auther when using quick setup
+ --password string hashed password for the first user when using quick config
+ -p, --port string port to listen on (default "8080")
+ -r, --root string root to prepend to relative paths (default ".")
+ --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
+ --socket-perm uint32 unix socket file permissions (default 438)
+ --token-expiration-time string user session timeout (default "2h")
+ --username string username for the first user when using quick config (default "admin")
+```
+
+## See Also
+
+* [filebrowser cmds](filebrowser-cmds.md) - Command runner management utility
+* [filebrowser completion](filebrowser-completion.md) - Generate the autocompletion script for the specified shell
+* [filebrowser config](filebrowser-config.md) - Configuration management utility
+* [filebrowser hash](filebrowser-hash.md) - Hashes a password
+* [filebrowser rules](filebrowser-rules.md) - Rules management utility
+* [filebrowser users](filebrowser-users.md) - Users management utility
+* [filebrowser version](filebrowser-version.md) - Print the version number
+
diff --git a/www/mkdocs.yml b/www/mkdocs.yml
index d489dcd5..a7fb41ea 100644
--- a/www/mkdocs.yml
+++ b/www/mkdocs.yml
@@ -34,8 +34,6 @@ theme:
features:
- navigation.tabs
- navigation.tabs.sticky
- - navigation.sections
- - navigation.expand
- navigation.indexes
- navigation.top
- navigation.instant
@@ -44,7 +42,6 @@ theme:
- search.share
- content.code.copy
- toc.follow
- - toc.integrate
icon:
repo: fontawesome/brands/github
@@ -97,10 +94,41 @@ extra:
nav:
- Home: index.md
- - Getting Started:
+ - Documentation:
- Installation: installation.md
- Configuration: configuration.md
- Deployment: deployment.md
+ - Command Line Usage:
+ - cli/filebrowser.md
+ - cli/filebrowser-cmds.md
+ - cli/filebrowser-cmds-add.md
+ - cli/filebrowser-cmds-ls.md
+ - cli/filebrowser-cmds-rm.md
+ - cli/filebrowser-completion.md
+ - cli/filebrowser-completion-bash.md
+ - cli/filebrowser-completion-fish.md
+ - cli/filebrowser-completion-powershell.md
+ - cli/filebrowser-completion-zsh.md
+ - cli/filebrowser-config.md
+ - cli/filebrowser-config-cat.md
+ - cli/filebrowser-config-export.md
+ - cli/filebrowser-config-import.md
+ - cli/filebrowser-config-init.md
+ - cli/filebrowser-config-set.md
+ - cli/filebrowser-hash.md
+ - cli/filebrowser-rules.md
+ - cli/filebrowser-rules-add.md
+ - cli/filebrowser-rules-ls.md
+ - cli/filebrowser-rules-rm.md
+ - cli/filebrowser-users.md
+ - cli/filebrowser-users-add.md
+ - cli/filebrowser-users-export.md
+ - cli/filebrowser-users-find.md
+ - cli/filebrowser-users-import.md
+ - cli/filebrowser-users-ls.md
+ - cli/filebrowser-users-rm.md
+ - cli/filebrowser-users-update.md
+ - cli/filebrowser-version.md
- Contributing:
- Contributing: contributing.md
- Code of Conduct: code-of-conduct.md
From d01493106dab0b85544c55c6ccc00a6d725986df Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 10:31:08 +0100
Subject: [PATCH 019/120] docs: improved config
---
www/docs/authentication.md | 49 +++++++++++
www/docs/command-execution.md | 54 ++++++++++++
www/docs/configuration.md | 152 ----------------------------------
www/docs/customization.md | 45 ++++++++++
www/docs/installation.md | 2 +-
www/mkdocs.yml | 5 +-
6 files changed, 153 insertions(+), 154 deletions(-)
create mode 100644 www/docs/authentication.md
create mode 100644 www/docs/command-execution.md
delete mode 100644 www/docs/configuration.md
create mode 100644 www/docs/customization.md
diff --git a/www/docs/authentication.md b/www/docs/authentication.md
new file mode 100644
index 00000000..365f9dac
--- /dev/null
+++ b/www/docs/authentication.md
@@ -0,0 +1,49 @@
+# Authentication
+
+There are three possible authentication methods. Each one of them has its own capabilities and specification. If you are interested in contributing with one more authentication method, please [check the guidelines](contributing.md).
+
+## JSON Auth (default)
+
+We call it JSON Authentication but it is just the default authentication method and the one that is provided by default if you don't make any changes. It is set by default, but if you've made changes before you can revert to using JSON auth:
+
+```sh
+filebrowser config set --auth.method=json
+```
+
+This method can also be extended with **reCAPTCHA** verification during login:
+
+```sh
+filebrowser config set --auth.method=json \
+ --recaptcha.key site-key \
+ --recaptcha.secret private-key
+```
+
+By default, we use [Google's reCAPTCHA](https://developers.google.com/recaptcha/docs/display) service. If you live in China, or want to use other provider, you can change the host with the following command:
+
+```sh
+filebrowser config set --recaptcha.host https://recaptcha.net
+```
+
+Where `https://recaptcha.net` is any provider you want.
+
+## Proxy Header
+
+If you have a reverse proxy you want to use to login your users, you do it via our `proxy` authentication method. To configure this method, your proxy must send an HTTP header containing the username of the logged in user:
+
+```sh
+filebrowser config set --auth.method=proxy --auth.header=X-My-Header
+```
+
+Where `X-My-Header` is the HTTP header provided by your proxy with the username.
+
+> [!WARNING]
+>
+> File Browser will blindly trust the provided header. If the proxy can be bypassed, an attacker could simply attach the header and get admin access.
+
+### No Authentication
+
+We also provide a no authentication mechanism for users that want to use File Browser privately such in a home network. By setting this authentication method, the user with **id 1** will be used as the default users. Creating more users won't have any effect.
+
+```sh
+filebrowser config set --auth.method=noauth
+```
diff --git a/www/docs/command-execution.md b/www/docs/command-execution.md
new file mode 100644
index 00000000..454c67b6
--- /dev/null
+++ b/www/docs/command-execution.md
@@ -0,0 +1,54 @@
+# Command Execution
+
+> [!CAUTION]
+>
+> The **hook runner** and **interactive shell** functionalities have been disabled for all existent and new installations by default from version v2.33.8 and onwards, due to continuous and known security vulnerabilities. You should only use this feature if you are aware of all of the security risks involved. For more up to date information, consult issue [#5199](https://github.com/filebrowser/filebrowser/issues/5199).
+
+## Hook Runner
+
+The hook runner is a feature that enables you to execute any shell command you want before or after a certain event. Right now, these are the events:
+
+* Copy
+* Rename
+* Upload
+* Delete
+* Save
+
+Also, during the execution of the commands set for those hooks, there will be some environment variables available to help you perform your commands:
+
+* `FILE` with the full absolute path to the changed file.
+* `SCOPE` with the path to user's scope.
+* `TRIGGER` with the name of the event.
+* `USERNAME` with the user's username.
+* `DESTINATION` with the absolute path to the destination. Only used for **copy** and **rename.**
+
+At this moment, you can edit the commands via the command line interface, using the following commands \(please check the flag `--help` to know more about them\):
+
+```bash
+filebrowser cmds add before_copy "echo $FILE"
+filebrowser cmds rm before_copy 0
+filebrowser cmds ls
+```
+
+Or you can use the web interface to manage them via **Settings** → **Global Settings**.
+
+## Interactive Shell
+
+Within File Browser you can toggle the shell (`< >` icon at the top right) and this will open a shell command window at the bottom of the screen. This functionality can be turned on using the environment variable `FB_DISABLE_EXEC=false` or the flag `--disable-exec=false`.
+
+By default no commands are available as the command list is empty. To enable commands these need to either be done on a per-user basis (including for the Admin user).
+
+You can do this by adding them in Settings > User Management > (edit user) > Commands or to *apply to all new users created from that point forward* they can be set in Settings > Global Settings
+
+> [!NOTE]
+>
+> If using a proxy manager then remember to enable websockets support for the File Browser proxy
+
+> [!NOTE]
+>
+> If using Docker and you want to add a new command that is not in the base image then you will need to build a custom Docker image using `filebrowser/filebrowser` as a base image. For example to add 7z:
+>
+> ```docker
+> FROM filebrowser/filebrowser
+> RUN sudo apt install p7zip-full
+> ```
diff --git a/www/docs/configuration.md b/www/docs/configuration.md
deleted file mode 100644
index 77f341a4..00000000
--- a/www/docs/configuration.md
+++ /dev/null
@@ -1,152 +0,0 @@
-# Configuration
-
-Most of the configuration can be understood through the command line interface documentation. To access it, you need to install File Browser and run `filebrowser --help`. In this page, we cover some specific, more complex, topics.
-
-## Custom Branding
-
-You can customize File Browser to use your own branding. This includes the following:
-
-- **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.
-
-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
-```
-
-> [!NOTE]
->
-> 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.
-
-### 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):
-
-```
-img/
- logo.svg
- icons/
- favicon.ico
- favicon.svg
- (...)
-```
-
-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.
-
-> [!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
-
-Right now, there are three possible authentication methods. Each one of them has its own capabilities and specification. If you are interested in contributing with one more authentication method, please [check the guidelines](contributing.md).
-
-### JSON Auth (default)
-
-We call it JSON Authentication but it is just the default authentication method and the one that is provided by default if you don't make any changes. It is set by default, but if you've made changes before you can revert to using JSON auth:
-
-```sh
-filebrowser config set --auth.method=json
-```
-
-This method can also be extended with **reCAPTCHA** verification during login:
-
-```sh
-filebrowser config set --auth.method=json \
- --recaptcha.key site-key \
- --recaptcha.secret private-key
-```
-
-By default, we use [Google's reCAPTCHA](https://developers.google.com/recaptcha/docs/display) service. If you live in China, or want to use other provider, you can change the host with the following command:
-
-```sh
-filebrowser config set --recaptcha.host https://recaptcha.net
-```
-
-Where `https://recaptcha.net` is any provider you want.
-
-### Proxy Header
-
-If you have a reverse proxy you want to use to login your users, you do it via our `proxy` authentication method. To configure this method, your proxy must send an HTTP header containing the username of the logged in user:
-
-```sh
-filebrowser config set --auth.method=proxy --auth.header=X-My-Header
-```
-
-Where `X-My-Header` is the HTTP header provided by your proxy with the username.
-
-> [!WARNING]
->
-> File Browser will blindly trust the provided header. If the proxy can be bypassed, an attacker could simply attach the header and get admin access.
-
-### No Authentication
-
-We also provide a no authentication mechanism for users that want to use File Browser privately such in a home network. By setting this authentication method, the user with **id 1** will be used as the default users. Creating more users won't have any effect.
-
-```sh
-filebrowser config set --auth.method=noauth
-```
-
-## Command Runner
-
-> [!CAUTION]
->
-> The **command execution** functionality has been disabled for all existent and new installations by default from version v2.33.8 and onwards, due to continuous and known security vulnerabilities. You should only use this feature if you are aware of all of the security risks involved. For more up to date information, consult issue [#5199](https://github.com/filebrowser/filebrowser/issues/5199).
-
-The command runner is a feature that enables you to execute any shell command you want before or after a certain event. Right now, these are the events:
-
-* Copy
-* Rename
-* Upload
-* Delete
-* Save
-
-Also, during the execution of the commands set for those hooks, there will be some environment variables available to help you perform your commands:
-
-* `FILE` with the full absolute path to the changed file.
-* `SCOPE` with the path to user's scope.
-* `TRIGGER` with the name of the event.
-* `USERNAME` with the user's username.
-* `DESTINATION` with the absolute path to the destination. Only used for **copy** and **rename.**
-
-At this moment, you can edit the commands via the command line interface, using the following commands \(please check the flag `--help` to know more about them\):
-
-```bash
-filebrowser cmds add before_copy "echo $FILE"
-filebrowser cmds rm before_copy 0
-filebrowser cmds ls
-```
-
-Or you can use the web interface to manage them via **Settings** → **Global Settings**.
-
-## Command Execution
-
-> [!CAUTION]
->
-> The **command execution** functionality has been disabled for all existent and new installations by default from version v2.33.8 and onwards, due to continuous and known security vulnerabilities. You should only use this feature if you are aware of all of the security risks involved. For more up to date information, consult issue [#5199](https://github.com/filebrowser/filebrowser/issues/5199).
-
-Within File Browser you can toggle the shell (`< >` icon at the top right) and this will open a shell command window at the bottom of the screen. This functionality can be turned on using the environment variable `FB_DISABLE_EXEC=false` or the flag `--disable-exec=false`.
-
-By default no commands are available as the command list is empty. To enable commands these need to either be done on a per-user basis (including for the Admin user).
-
-You can do this by adding them in Settings > User Management > (edit user) > Commands or to *apply to all new users created from that point forward* they can be set in Settings > Global Settings
-
-> [!NOTE]
->
-> If using a proxy manager then remember to enable websockets support for the File Browser proxy
-
-> [!NOTE]
->
-> If using Docker and you want to add a new command that is not in the base image then you will need to build a custom Docker image using `filebrowser/filebrowser` as a base image. For example to add 7z:
->
-> ```docker
-> FROM filebrowser/filebrowser
-> RUN sudo apt install p7zip-full
-> ```
diff --git a/www/docs/customization.md b/www/docs/customization.md
new file mode 100644
index 00000000..054da7ab
--- /dev/null
+++ b/www/docs/customization.md
@@ -0,0 +1,45 @@
+# Customization
+
+You can customize the styles, branding and icons of your File Browser instance in order to give it a personal touch.
+
+## Custom Branding
+
+You can customize File Browser to use your own branding. This includes the following:
+
+- **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.
+
+This can be configured by the administrator user, under **Settings → Global Settings**. You can also update the configuration directly using the [CLI](cli/filebrowser-config-set.md):
+
+```sh
+filebrowser config set --branding.name "My Name" \
+ --branding.files "/abs/path/to/my/dir" \
+ --branding.disableExternal
+```
+
+> [!NOTE]
+>
+> 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.
+
+### 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):
+
+```
+img/
+ logo.svg
+ icons/
+ favicon.ico
+ favicon.svg
+ (...)
+```
+
+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.
+
+> [!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.
diff --git a/www/docs/installation.md b/www/docs/installation.md
index 741e8c1a..6acb8db6 100644
--- a/www/docs/installation.md
+++ b/www/docs/installation.md
@@ -88,6 +88,6 @@ Your instance is now up and running. File Browser will automatically bootstrap a
>
> The automatically generated password for the user `admin` is only displayed once. If you fail to remember it, you will need to manually delete the database and start File Browser again.
-Although this is the fastest way to bootstrap an instance, we recommend you to take a look at other possible options, by checking `config init --help` and `config set --help`, to make the installation as safe and customized as it can be.
+Although this is the fastest way to bootstrap an instance, we recommend you to take a look at other possible options, by checking [`config init`](cli/filebrowser-config-init.md) and [`config set`](cli/filebrowser-config-set.md), to make the installation as safe and customized as it can be.
If your goal is to have a public-facing deployment, we recommend taking a look at the [deployment](deployment.md) page for more information on how you can secure your installation.
diff --git a/www/mkdocs.yml b/www/mkdocs.yml
index a7fb41ea..7558c534 100644
--- a/www/mkdocs.yml
+++ b/www/mkdocs.yml
@@ -96,7 +96,10 @@ nav:
- Home: index.md
- Documentation:
- Installation: installation.md
- - Configuration: configuration.md
+ - Configuration:
+ - customization.md
+ - authentication.md
+ - command-execution.md
- Deployment: deployment.md
- Command Line Usage:
- cli/filebrowser.md
From 5de4099cba2cf012d4a213c8eb29c412fc72c151 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 14:13:21 +0100
Subject: [PATCH 020/120] fix: exit 0 when gracefully shutting down (#5555)
---
cmd/root.go | 14 +------------
cmd/utils.go | 1 -
errors/errors.go | 54 ------------------------------------------------
main.go | 3 +--
4 files changed, 2 insertions(+), 70 deletions(-)
diff --git a/cmd/root.go b/cmd/root.go
index 24f5d077..0d103b29 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -26,7 +26,6 @@ import (
"github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/diskcache"
- fbErrors "github.com/filebrowser/filebrowser/v2/errors"
"github.com/filebrowser/filebrowser/v2/frontend"
fbhttp "github.com/filebrowser/filebrowser/v2/http"
"github.com/filebrowser/filebrowser/v2/img"
@@ -241,18 +240,7 @@ user created with the credentials from options "username" and "password".`,
}
log.Println("Graceful shutdown complete.")
- switch sig {
- case syscall.SIGHUP:
- d.err = fbErrors.ErrSighup
- case syscall.SIGINT:
- d.err = fbErrors.ErrSigint
- case syscall.SIGQUIT:
- d.err = fbErrors.ErrSigquit
- case syscall.SIGTERM:
- d.err = fbErrors.ErrSigTerm
- }
-
- return d.err
+ return nil
}, pythonConfig{allowNoDB: true}),
}
diff --git a/cmd/utils.go b/cmd/utils.go
index cc718341..3ed5c989 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -66,7 +66,6 @@ type pythonConfig struct {
type pythonData struct {
hadDB bool
store *storage.Storage
- err error
}
func dbExists(path string) (bool, error) {
diff --git a/errors/errors.go b/errors/errors.go
index f8abee59..5fd760c2 100644
--- a/errors/errors.go
+++ b/errors/errors.go
@@ -3,15 +3,6 @@ package errors
import (
"errors"
"fmt"
- "os"
- "syscall"
-)
-
-const (
- ExitCodeSigTerm = 128 + int(syscall.SIGTERM)
- ExitCodeSighup = 128 + int(syscall.SIGHUP)
- ExitCodeSigint = 128 + int(syscall.SIGINT)
- ExitCodeSigquit = 128 + int(syscall.SIGQUIT)
)
var (
@@ -31,10 +22,6 @@ var (
ErrInvalidRequestParams = errors.New("invalid request params")
ErrSourceIsParent = errors.New("source is parent")
ErrRootUserDeletion = errors.New("user with id 1 can't be deleted")
- ErrSigTerm = errors.New("exit on signal: sigterm")
- ErrSighup = errors.New("exit on signal: sighup")
- ErrSigint = errors.New("exit on signal: sigint")
- ErrSigquit = errors.New("exit on signal: sigquit")
)
type ErrShortPassword struct {
@@ -44,44 +31,3 @@ type ErrShortPassword struct {
func (e ErrShortPassword) Error() string {
return fmt.Sprintf("password is too short, minimum length is %d", e.MinimumLength)
}
-
-// GetExitCode returns the exit code for a given error.
-func GetExitCode(err error) int {
- if err == nil {
- return 0
- }
-
- exitCodeMap := map[error]int{
- ErrSigTerm: ExitCodeSigTerm,
- ErrSighup: ExitCodeSighup,
- ErrSigint: ExitCodeSigint,
- ErrSigquit: ExitCodeSigquit,
- }
-
- for e, code := range exitCodeMap {
- if errors.Is(err, e) {
- return code
- }
- }
-
- if exitErr, ok := err.(interface{ ExitCode() int }); ok {
- return exitErr.ExitCode()
- }
-
- var pathErr *os.PathError
- if errors.As(err, &pathErr) {
- return 1
- }
-
- var syscallErr *os.SyscallError
- if errors.As(err, &syscallErr) {
- return 1
- }
-
- var errno syscall.Errno
- if errors.As(err, &errno) {
- return 1
- }
-
- return 1
-}
diff --git a/main.go b/main.go
index d17550c9..bde39461 100644
--- a/main.go
+++ b/main.go
@@ -4,11 +4,10 @@ import (
"os"
"github.com/filebrowser/filebrowser/v2/cmd"
- "github.com/filebrowser/filebrowser/v2/errors"
)
func main() {
if err := cmd.Execute(); err != nil {
- os.Exit(errors.GetExitCode(err))
+ os.Exit(1)
}
}
From e24e1f1abae9e80add620c4ad65660ca1b575a49 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 14:13:58 +0100
Subject: [PATCH 021/120] feat: add TUS settings to the command line (#5556)
---
cmd/config.go | 10 ++++++++--
cmd/config_init.go | 14 ++++++++++++++
cmd/config_set.go | 4 ++++
3 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/cmd/config.go b/cmd/config.go
index 84474f4c..6b739610 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -52,8 +52,11 @@ func addConfigFlags(flags *pflag.FlagSet) {
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
// NB: these are string so they can be presented as octal in the help text
// as that's the conventional representation for modes in Unix.
- flags.String("file-mode", fmt.Sprintf("%O", settings.DefaultFileMode), "Mode bits that new files are created with")
- flags.String("dir-mode", fmt.Sprintf("%O", settings.DefaultDirMode), "Mode bits that new directories are created with")
+ flags.String("file-mode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with")
+ flags.String("dir-mode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with")
+
+ flags.Uint64("tus.chunkSize", settings.DefaultTusChunkSize, "the tus chunk size")
+ flags.Uint16("tus.retryCount", settings.DefaultTusRetryCount, "the tus retry count")
}
func getAuthMethod(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, map[string]interface{}, error) {
@@ -215,6 +218,9 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
+ fmt.Fprintln(w, "\nTUS:")
+ fmt.Fprintf(w, "\tChunk size:\t%d\n", set.Tus.ChunkSize)
+ fmt.Fprintf(w, "\tRetry count:\t%d\n", set.Tus.RetryCount)
fmt.Fprintln(w, "\nDefaults:")
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
fmt.Fprintf(w, "\tHideDotfiles:\t%t\n", set.Defaults.HideDotfiles)
diff --git a/cmd/config_init.go b/cmd/config_init.go
index 693b6ace..47d02d8a 100644
--- a/cmd/config_init.go
+++ b/cmd/config_init.go
@@ -86,6 +86,16 @@ override the options.`,
return err
}
+ tusChunkSize, err := flags.GetUint64("tus.chunkSize")
+ if err != nil {
+ return err
+ }
+
+ tusRetryCount, err := flags.GetUint16("tus.retryCount")
+ if err != nil {
+ return err
+ }
+
s := &settings.Settings{
Key: key,
Signup: signup,
@@ -102,6 +112,10 @@ override the options.`,
Theme: brandingTheme,
Files: brandingFiles,
},
+ Tus: settings.Tus{
+ ChunkSize: tusChunkSize,
+ RetryCount: tusRetryCount,
+ },
}
s.FileMode, err = getMode(flags, "file-mode")
diff --git a/cmd/config_set.go b/cmd/config_set.go
index 255ef470..c362e2e1 100644
--- a/cmd/config_set.go
+++ b/cmd/config_set.go
@@ -80,6 +80,10 @@ you want to change. Other options will remain unchanged.`,
set.FileMode, err = getMode(flags, flag.Name)
case "dir-mode":
set.DirMode, err = getMode(flags, flag.Name)
+ case "tus.chunkSize":
+ set.Tus.ChunkSize, err = flags.GetUint64(flag.Name)
+ case "tus.retryCount":
+ set.Tus.RetryCount, err = flags.GetUint16(flag.Name)
}
})
From 0fadaccaa2e2715c7917a2e26f1a47528cf1810d Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 14:28:03 +0100
Subject: [PATCH 022/120] chore(docs): update CLI documentation
---
www/docs/cli/filebrowser-config-init.md | 6 ++++--
www/docs/cli/filebrowser-config-set.md | 6 ++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/www/docs/cli/filebrowser-config-init.md b/www/docs/cli/filebrowser-config-init.md
index f317c9a0..126082d0 100644
--- a/www/docs/cli/filebrowser-config-init.md
+++ b/www/docs/cli/filebrowser-config-init.md
@@ -34,12 +34,12 @@ filebrowser config init [flags]
--commands strings a list of the commands a user can execute
--create-user-dir generate user's home directory automatically
--dateFormat use date format (true for absolute time, false for relative)
- --dir-mode string Mode bits that new directories are created with (default "0o750")
+ --dir-mode string mode bits that new directories are created with (default "0o750")
--disable-exec disables Command Runner feature (default true)
--disable-preview-resize disable resize of image previews
--disable-thumbnails disable image thumbnails
--disable-type-detection-by-header disables type detection by reading file headers
- --file-mode string Mode bits that new files are created with (default "0o640")
+ --file-mode string mode bits that new files are created with (default "0o640")
-h, --help help for init
--hide-login-button hide login button from public pages
--hideDotfiles hide dotfiles
@@ -71,6 +71,8 @@ filebrowser config init [flags]
--sorting.asc sorting by ascending order
--sorting.by string sorting mode (name, size or modified) (default "name")
--token-expiration-time string user session timeout (default "2h")
+ --tus.chunkSize uint the tus chunk size (default 10485760)
+ --tus.retryCount uint16 the tus retry count (default 5)
--viewMode string view mode for users (default "list")
```
diff --git a/www/docs/cli/filebrowser-config-set.md b/www/docs/cli/filebrowser-config-set.md
index a396ab13..8d8ea8f5 100644
--- a/www/docs/cli/filebrowser-config-set.md
+++ b/www/docs/cli/filebrowser-config-set.md
@@ -31,12 +31,12 @@ filebrowser config set [flags]
--commands strings a list of the commands a user can execute
--create-user-dir generate user's home directory automatically
--dateFormat use date format (true for absolute time, false for relative)
- --dir-mode string Mode bits that new directories are created with (default "0o750")
+ --dir-mode string mode bits that new directories are created with (default "0o750")
--disable-exec disables Command Runner feature (default true)
--disable-preview-resize disable resize of image previews
--disable-thumbnails disable image thumbnails
--disable-type-detection-by-header disables type detection by reading file headers
- --file-mode string Mode bits that new files are created with (default "0o640")
+ --file-mode string mode bits that new files are created with (default "0o640")
-h, --help help for set
--hide-login-button hide login button from public pages
--hideDotfiles hide dotfiles
@@ -68,6 +68,8 @@ filebrowser config set [flags]
--sorting.asc sorting by ascending order
--sorting.by string sorting mode (name, size or modified) (default "name")
--token-expiration-time string user session timeout (default "2h")
+ --tus.chunkSize uint the tus chunk size (default 10485760)
+ --tus.retryCount uint16 the tus retry count (default 5)
--viewMode string view mode for users (default "list")
```
From fb8d41eb9a4f0027bb346c4981982acac2214caf Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 14:28:15 +0100
Subject: [PATCH 023/120] chore(release): 2.47.0
---
CHANGELOG.md | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70d61c71..5c25523b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,19 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [2.47.0](https://github.com/filebrowser/filebrowser/compare/v2.46.1...v2.47.0) (2025-11-16)
+
+
+### Features
+
+* add TUS settings to the command line ([#5556](https://github.com/filebrowser/filebrowser/issues/5556)) ([e24e1f1](https://github.com/filebrowser/filebrowser/commit/e24e1f1abae9e80add620c4ad65660ca1b575a49))
+* remove importer of v1 config ([#5550](https://github.com/filebrowser/filebrowser/issues/5550)) ([ceb5e72](https://github.com/filebrowser/filebrowser/commit/ceb5e723f3ee2c966bb561a804015246450280ca))
+
+
+### Bug Fixes
+
+* exit 0 when gracefully shutting down ([#5555](https://github.com/filebrowser/filebrowser/issues/5555)) ([5de4099](https://github.com/filebrowser/filebrowser/commit/5de4099cba2cf012d4a213c8eb29c412fc72c151))
+
## [2.46.1](https://github.com/filebrowser/filebrowser/compare/v2.46.0...v2.46.1) (2025-11-15)
From f89435c068110b1470f29e4cbff28c63de9b5397 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Sun, 16 Nov 2025 14:28:48 +0100
Subject: [PATCH 024/120] chore: fix taskfile
---
Taskfile.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Taskfile.yml b/Taskfile.yml
index 855507bc..5977dff0 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -49,6 +49,7 @@ tasks:
cmds:
- task: docs:cli:generate
- git add www/docs/cli
+ - "git commit -m 'chore(docs): update CLI documentation'"
- task: release:dry-run
- task: release:make
From 0a0cb8046fce52f1ff926171b34bcdb7cd39aab3 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 08:45:43 +0100
Subject: [PATCH 025/120] feat: consistent flags and environment variables
(#5549)
- In the root command, all flags are now correctly available as environmental variables, except for `--config` flag. This was already supposed to be the case, but due to bugs in the implementation it didn't work properly.
- All configuration options (unless I missed something) that are available as flags should now properly update the configuration when using the `config init` and `config set` commands.
- Flag names are now consistently in the lowerCamelCase format. All flags that were in a different format have been updated in a backwards compatible way. For a transitionary period of at least 6 months, both will work:
- `--dir-mode` --> `--dirMode`
- `--hide-login-button` --> `--hideLoginButton`
- `--create-user-dir` --> `--createUserDir`
- `--minimum-password-length` --> `--minimumPasswordLength`
- `--socket-perm` --> `--socketPerm`
- `--disable-thumbnails` --> `--disableThumbnails`
- `--disable-preview-resize` --> `--disablePreviewResize`
- `--disable-exec` --> `--disableExec`
- `--disable-type-detection-by-header` --> `--disableTypeDetectionByHeader`
- `--img-processors` --> `--imageProcessors`
- `--cache-dir` --> `--cacheDir`
- `--token-expiration-time` --> `--tokenExpirationTime`
- `--baseurl` --> `--baseURL`
---
cmd/cmd_test.go | 35 ++++++
cmd/cmds_ls.go | 4 +-
cmd/config.go | 37 ++++--
cmd/config_import.go | 4 +-
cmd/config_init.go | 198 ++++++++++++++----------------
cmd/config_set.go | 99 +++++++++------
cmd/root.go | 283 ++++++++++++++++---------------------------
cmd/rules.go | 5 +-
cmd/rules_add.go | 8 +-
cmd/users.go | 50 ++++----
cmd/users_add.go | 40 +++---
cmd/users_import.go | 5 +-
cmd/users_update.go | 19 +--
cmd/utils.go | 150 +++++++++++++++++------
go.mod | 1 +
go.sum | 2 +
16 files changed, 503 insertions(+), 437 deletions(-)
create mode 100644 cmd/cmd_test.go
diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go
new file mode 100644
index 00000000..e4b45c47
--- /dev/null
+++ b/cmd/cmd_test.go
@@ -0,0 +1,35 @@
+package cmd
+
+import (
+ "testing"
+
+ "github.com/samber/lo"
+ "github.com/spf13/cobra"
+)
+
+// TestEnvCollisions ensures that there are no collisions in the produced environment
+// variable names for all commands and their flags.
+func TestEnvCollisions(t *testing.T) {
+ testEnvCollisions(t, rootCmd)
+}
+
+func testEnvCollisions(t *testing.T, cmd *cobra.Command) {
+ for _, cmd := range cmd.Commands() {
+ testEnvCollisions(t, cmd)
+ }
+
+ replacements := generateEnvKeyReplacements(cmd)
+ envVariables := []string{}
+
+ for i := range replacements {
+ if i%2 != 0 {
+ envVariables = append(envVariables, replacements[i])
+ }
+ }
+
+ duplicates := lo.FindDuplicates(envVariables)
+
+ if len(duplicates) > 0 {
+ t.Errorf("Found duplicate environment variable keys for command %q: %v", cmd.Name(), duplicates)
+ }
+}
diff --git a/cmd/cmds_ls.go b/cmd/cmds_ls.go
index fa901a56..ad700eb7 100644
--- a/cmd/cmds_ls.go
+++ b/cmd/cmds_ls.go
@@ -19,7 +19,8 @@ var cmdsLsCmd = &cobra.Command{
if err != nil {
return err
}
- evt, err := getString(cmd.Flags(), "event")
+
+ evt, err := cmd.Flags().GetString("event")
if err != nil {
return err
}
@@ -32,6 +33,7 @@ var cmdsLsCmd = &cobra.Command{
show["after_"+evt] = s.Commands["after_"+evt]
printEvents(show)
}
+
return nil
}, pythonConfig{}),
}
diff --git a/cmd/config.go b/cmd/config.go
index 6b739610..73d4faa9 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -30,10 +30,11 @@ var configCmd = &cobra.Command{
func addConfigFlags(flags *pflag.FlagSet) {
addServerFlags(flags)
addUserFlags(flags)
+
flags.BoolP("signup", "s", false, "allow users to signup")
- flags.Bool("hide-login-button", false, "hide login button from public pages")
- flags.Bool("create-user-dir", false, "generate user's home directory automatically")
- flags.Uint("minimum-password-length", settings.DefaultMinimumPasswordLength, "minimum password length for new users")
+ flags.Bool("hideLoginButton", false, "hide login button from public pages")
+ flags.Bool("createUserDir", false, "generate user's home directory automatically")
+ flags.Uint("minimumPasswordLength", settings.DefaultMinimumPasswordLength, "minimum password length for new users")
flags.String("shell", "", "shell command to which other commands should be appended")
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
@@ -50,17 +51,18 @@ func addConfigFlags(flags *pflag.FlagSet) {
flags.String("branding.files", "", "path to directory with images and custom styles")
flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
+
// NB: these are string so they can be presented as octal in the help text
// as that's the conventional representation for modes in Unix.
- flags.String("file-mode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with")
- flags.String("dir-mode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with")
+ flags.String("fileMode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with")
+ flags.String("dirMode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with")
flags.Uint64("tus.chunkSize", settings.DefaultTusChunkSize, "the tus chunk size")
flags.Uint16("tus.retryCount", settings.DefaultTusRetryCount, "the tus retry count")
}
func getAuthMethod(flags *pflag.FlagSet, defaults ...interface{}) (settings.AuthMethod, map[string]interface{}, error) {
- methodStr, err := getString(flags, "auth.method")
+ methodStr, err := flags.GetString("auth.method")
if err != nil {
return "", nil, err
}
@@ -91,7 +93,7 @@ func getAuthMethod(flags *pflag.FlagSet, defaults ...interface{}) (settings.Auth
}
func getProxyAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) {
- header, err := getString(flags, "auth.header")
+ header, err := flags.GetString("auth.header")
if err != nil {
return nil, err
}
@@ -113,15 +115,17 @@ func getNoAuth() auth.Auther {
func getJSONAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) {
jsonAuth := &auth.JSONAuth{}
- host, err := getString(flags, "recaptcha.host")
+ host, err := flags.GetString("recaptcha.host")
if err != nil {
return nil, err
}
- key, err := getString(flags, "recaptcha.key")
+
+ key, err := flags.GetString("recaptcha.key")
if err != nil {
return nil, err
}
- secret, err := getString(flags, "recaptcha.secret")
+
+ secret, err := flags.GetString("recaptcha.secret")
if err != nil {
return nil, err
}
@@ -149,11 +153,10 @@ func getJSONAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (au
}
func getHookAuth(flags *pflag.FlagSet, defaultAuther map[string]interface{}) (auth.Auther, error) {
- command, err := getString(flags, "auth.command")
+ command, err := flags.GetString("auth.command")
if err != nil {
return nil, err
}
-
if command == "" {
command = defaultAuther["command"].(string)
}
@@ -201,6 +204,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "Minimum Password Length:\t%d\n", set.MinimumPasswordLength)
fmt.Fprintf(w, "Auth Method:\t%s\n", set.AuthMethod)
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
+
fmt.Fprintln(w, "\nBranding:")
fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
@@ -208,6 +212,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Branding.DisableUsedPercentage)
fmt.Fprintf(w, "\tColor:\t%s\n", set.Branding.Color)
fmt.Fprintf(w, "\tTheme:\t%s\n", set.Branding.Theme)
+
fmt.Fprintln(w, "\nServer:")
fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
@@ -218,9 +223,14 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
+ fmt.Fprintf(w, "\tThumbnails Enabled:\t%t\n", ser.EnableThumbnails)
+ fmt.Fprintf(w, "\tResize Preview:\t%t\n", ser.ResizePreview)
+ fmt.Fprintf(w, "\tType Detection by Header:\t%t\n", ser.TypeDetectionByHeader)
+
fmt.Fprintln(w, "\nTUS:")
fmt.Fprintf(w, "\tChunk size:\t%d\n", set.Tus.ChunkSize)
fmt.Fprintf(w, "\tRetry count:\t%d\n", set.Tus.RetryCount)
+
fmt.Fprintln(w, "\nDefaults:")
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
fmt.Fprintf(w, "\tHideDotfiles:\t%t\n", set.Defaults.HideDotfiles)
@@ -231,9 +241,11 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tDirectory Creation Mode:\t%O\n", set.DirMode)
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
fmt.Fprintf(w, "\tAce editor syntax highlighting theme:\t%s\n", set.Defaults.AceEditorTheme)
+
fmt.Fprintf(w, "\tSorting:\n")
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
+
fmt.Fprintf(w, "\tPermissions:\n")
fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
@@ -243,6 +255,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
+
w.Flush()
b, err := json.MarshalIndent(auther, "", " ")
diff --git a/cmd/config_import.go b/cmd/config_import.go
index 7763517d..63d394d7 100644
--- a/cmd/config_import.go
+++ b/cmd/config_import.go
@@ -37,7 +37,7 @@ The path must be for a json or yaml file.`,
RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
var key []byte
var err error
- if d.hadDB {
+ if d.databaseExisted {
settings, settingErr := d.store.Settings.Get()
if settingErr != nil {
return settingErr
@@ -104,7 +104,7 @@ The path must be for a json or yaml file.`,
}
return printSettings(file.Server, file.Settings, auther)
- }, pythonConfig{allowNoDB: true}),
+ }, pythonConfig{allowsNoDatabase: true}),
}
func getAuther(sample auth.Auther, data interface{}) (interface{}, error) {
diff --git a/cmd/config_init.go b/cmd/config_init.go
index 47d02d8a..21cacb33 100644
--- a/cmd/config_init.go
+++ b/cmd/config_init.go
@@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
+ "github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/settings"
)
@@ -23,170 +24,147 @@ to the defaults when creating new users and you don't
override the options.`,
Args: cobra.NoArgs,
RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
- defaults := settings.UserDefaults{}
flags := cmd.Flags()
- err := getUserDefaults(flags, &defaults, true)
- if err != nil {
- return err
- }
- authMethod, auther, err := getAuthentication(flags)
- if err != nil {
- return err
- }
-
- key := generateKey()
-
- signup, err := getBool(flags, "signup")
- if err != nil {
- return err
- }
-
- hideLoginButton, err := getBool(flags, "hide-login-button")
- if err != nil {
- return err
- }
-
- createUserDir, err := getBool(flags, "create-user-dir")
- if err != nil {
- return err
- }
-
- minLength, err := getUint(flags, "minimum-password-length")
- if err != nil {
- return err
- }
-
- shell, err := getString(flags, "shell")
- if err != nil {
- return err
- }
-
- brandingName, err := getString(flags, "branding.name")
- if err != nil {
- return err
- }
-
- brandingDisableExternal, err := getBool(flags, "branding.disableExternal")
- if err != nil {
- return err
- }
-
- brandingDisableUsedPercentage, err := getBool(flags, "branding.disableUsedPercentage")
- if err != nil {
- return err
- }
-
- brandingTheme, err := getString(flags, "branding.theme")
- if err != nil {
- return err
- }
-
- brandingFiles, err := getString(flags, "branding.files")
- if err != nil {
- return err
- }
-
- tusChunkSize, err := flags.GetUint64("tus.chunkSize")
- if err != nil {
- return err
- }
-
- tusRetryCount, err := flags.GetUint16("tus.retryCount")
- if err != nil {
- return err
- }
+ // General Settings
s := &settings.Settings{
- Key: key,
- Signup: signup,
- HideLoginButton: hideLoginButton,
- CreateUserDir: createUserDir,
- MinimumPasswordLength: minLength,
- Shell: convertCmdStrToCmdArray(shell),
- AuthMethod: authMethod,
- Defaults: defaults,
- Branding: settings.Branding{
- Name: brandingName,
- DisableExternal: brandingDisableExternal,
- DisableUsedPercentage: brandingDisableUsedPercentage,
- Theme: brandingTheme,
- Files: brandingFiles,
- },
- Tus: settings.Tus{
- ChunkSize: tusChunkSize,
- RetryCount: tusRetryCount,
- },
+ Key: generateKey(),
}
- s.FileMode, err = getMode(flags, "file-mode")
+ err := getUserDefaults(flags, &s.Defaults, true)
if err != nil {
return err
}
- s.DirMode, err = getMode(flags, "dir-mode")
+ s.Signup, err = flags.GetBool("signup")
if err != nil {
return err
}
- address, err := getString(flags, "address")
+ s.HideLoginButton, err = flags.GetBool("hideLoginButton")
if err != nil {
return err
}
- socket, err := getString(flags, "socket")
+ s.CreateUserDir, err = flags.GetBool("createUserDir")
if err != nil {
return err
}
- root, err := getString(flags, "root")
+ s.MinimumPasswordLength, err = flags.GetUint("minimumPasswordLength")
if err != nil {
return err
}
- baseURL, err := getString(flags, "baseurl")
+ shell, err := flags.GetString("shell")
+ if err != nil {
+ return err
+ }
+ s.Shell = convertCmdStrToCmdArray(shell)
+
+ s.FileMode, err = getAndParseFileMode(flags, "fileMode")
if err != nil {
return err
}
- tlsKey, err := getString(flags, "key")
+ s.DirMode, err = getAndParseFileMode(flags, "dirMode")
if err != nil {
return err
}
- cert, err := getString(flags, "cert")
+ s.Branding.Name, err = flags.GetString("branding.name")
if err != nil {
return err
}
- port, err := getString(flags, "port")
+ s.Branding.DisableExternal, err = flags.GetBool("branding.disableExternal")
if err != nil {
return err
}
- log, err := getString(flags, "log")
+ s.Branding.DisableUsedPercentage, err = flags.GetBool("branding.disableUsedPercentage")
if err != nil {
return err
}
- ser := &settings.Server{
- Address: address,
- Socket: socket,
- Root: root,
- BaseURL: baseURL,
- TLSKey: tlsKey,
- TLSCert: cert,
- Port: port,
- Log: log,
+ s.Branding.Theme, err = flags.GetString("branding.themes")
+ if err != nil {
+ return err
+ }
+
+ s.Branding.Files, err = flags.GetString("branding.files")
+ if err != nil {
+ return err
+ }
+
+ s.Tus.ChunkSize, err = flags.GetUint64("tus.chunkSize")
+ if err != nil {
+ return err
+ }
+
+ s.Tus.RetryCount, err = flags.GetUint16("tus.retryCount")
+ if err != nil {
+ return err
+ }
+
+ var auther auth.Auther
+ s.AuthMethod, auther, err = getAuthentication(flags)
+ if err != nil {
+ return err
+ }
+
+ // Server Settings
+ ser := &settings.Server{}
+ ser.Address, err = flags.GetString("address")
+ if err != nil {
+ return err
+ }
+
+ ser.Socket, err = flags.GetString("socket")
+ if err != nil {
+ return err
+ }
+
+ ser.Root, err = flags.GetString("root")
+ if err != nil {
+ return err
+ }
+
+ ser.BaseURL, err = flags.GetString("baseURL")
+ if err != nil {
+ return err
+ }
+
+ ser.TLSKey, err = flags.GetString("key")
+ if err != nil {
+ return err
+ }
+
+ ser.TLSCert, err = flags.GetString("cert")
+ if err != nil {
+ return err
+ }
+
+ ser.Port, err = flags.GetString("port")
+ if err != nil {
+ return err
+ }
+
+ ser.Log, err = flags.GetString("log")
+ if err != nil {
+ return err
}
err = d.store.Settings.Save(s)
if err != nil {
return err
}
+
err = d.store.Settings.SaveServer(ser)
if err != nil {
return err
}
+
err = d.store.Auth.Save(auther)
if err != nil {
return err
@@ -198,5 +176,5 @@ Now add your first user via 'filebrowser users add' and then you just
need to call the main command to boot up the server.
`)
return printSettings(ser, s, auther)
- }, pythonConfig{noDB: true}),
+ }, pythonConfig{expectsNoDatabase: true}),
}
diff --git a/cmd/config_set.go b/cmd/config_set.go
index c362e2e1..74fae9ea 100644
--- a/cmd/config_set.go
+++ b/cmd/config_set.go
@@ -18,6 +18,7 @@ you want to change. Other options will remain unchanged.`,
Args: cobra.NoArgs,
RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
flags := cmd.Flags()
+
set, err := d.store.Settings.Get()
if err != nil {
return err
@@ -29,64 +30,86 @@ you want to change. Other options will remain unchanged.`,
}
hasAuth := false
+
flags.Visit(func(flag *pflag.Flag) {
if err != nil {
return
}
+
switch flag.Name {
- case "baseurl":
- ser.BaseURL, err = getString(flags, flag.Name)
- case "root":
- ser.Root, err = getString(flags, flag.Name)
- case "socket":
- ser.Socket, err = getString(flags, flag.Name)
- case "cert":
- ser.TLSCert, err = getString(flags, flag.Name)
- case "key":
- ser.TLSKey, err = getString(flags, flag.Name)
+ // Server flags from [addServerFlags]
case "address":
- ser.Address, err = getString(flags, flag.Name)
- case "port":
- ser.Port, err = getString(flags, flag.Name)
+ ser.Address, err = flags.GetString(flag.Name)
case "log":
- ser.Log, err = getString(flags, flag.Name)
- case "hide-login-button":
- set.HideLoginButton, err = getBool(flags, flag.Name)
+ ser.Log, err = flags.GetString(flag.Name)
+ case "port":
+ ser.Port, err = flags.GetString(flag.Name)
+ case "cert":
+ ser.TLSCert, err = flags.GetString(flag.Name)
+ case "key":
+ ser.TLSKey, err = flags.GetString(flag.Name)
+ case "root":
+ ser.Root, err = flags.GetString(flag.Name)
+ case "socket":
+ ser.Socket, err = flags.GetString(flag.Name)
+ case "baseURL":
+ ser.BaseURL, err = flags.GetString(flag.Name)
+ case "tokenExpirationTime":
+ ser.TokenExpirationTime, err = flags.GetString(flag.Name)
+ case "disableThumbnails":
+ ser.EnableThumbnails, err = flags.GetBool(flag.Name)
+ ser.EnableThumbnails = !ser.EnableThumbnails
+ case "disablePreviewResize":
+ ser.ResizePreview, err = flags.GetBool(flag.Name)
+ ser.ResizePreview = !ser.ResizePreview
+ case "disableExec":
+ ser.EnableExec, err = flags.GetBool(flag.Name)
+ ser.EnableExec = !ser.EnableExec
+ case "disableTypeDetectionByHeader":
+ ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name)
+ ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader
+
+ // Settings flags from [addConfigFlags]
case "signup":
- set.Signup, err = getBool(flags, flag.Name)
- case "auth.method":
- hasAuth = true
+ set.Signup, err = flags.GetBool(flag.Name)
+ case "hideLoginButton":
+ set.HideLoginButton, err = flags.GetBool(flag.Name)
+ case "createUserDir":
+ set.CreateUserDir, err = flags.GetBool(flag.Name)
+ case "minimumPasswordLength":
+ set.MinimumPasswordLength, err = flags.GetUint(flag.Name)
case "shell":
var shell string
- shell, err = getString(flags, flag.Name)
+ shell, err = flags.GetString(flag.Name)
+ if err != nil {
+ return
+ }
set.Shell = convertCmdStrToCmdArray(shell)
- case "create-user-dir":
- set.CreateUserDir, err = getBool(flags, flag.Name)
- case "minimum-password-length":
- set.MinimumPasswordLength, err = getUint(flags, flag.Name)
+ case "auth.method":
+ hasAuth = true
case "branding.name":
- set.Branding.Name, err = getString(flags, flag.Name)
- case "branding.color":
- set.Branding.Color, err = getString(flags, flag.Name)
+ set.Branding.Name, err = flags.GetString(flag.Name)
case "branding.theme":
- set.Branding.Theme, err = getString(flags, flag.Name)
- case "branding.disableExternal":
- set.Branding.DisableExternal, err = getBool(flags, flag.Name)
- case "branding.disableUsedPercentage":
- set.Branding.DisableUsedPercentage, err = getBool(flags, flag.Name)
+ set.Branding.Theme, err = flags.GetString(flag.Name)
+ case "branding.color":
+ set.Branding.Color, err = flags.GetString(flag.Name)
case "branding.files":
- set.Branding.Files, err = getString(flags, flag.Name)
- case "file-mode":
- set.FileMode, err = getMode(flags, flag.Name)
- case "dir-mode":
- set.DirMode, err = getMode(flags, flag.Name)
+ set.Branding.Files, err = flags.GetString(flag.Name)
+ case "branding.disableExternal":
+ set.Branding.DisableExternal, err = flags.GetBool(flag.Name)
+ case "branding.disableUsedPercentage":
+ set.Branding.DisableUsedPercentage, err = flags.GetBool(flag.Name)
+ case "fileMode":
+ set.FileMode, err = getAndParseFileMode(flags, flag.Name)
+ case "dirMode":
+ set.DirMode, err = getAndParseFileMode(flags, flag.Name)
case "tus.chunkSize":
set.Tus.ChunkSize, err = flags.GetUint64(flag.Name)
case "tus.retryCount":
set.Tus.RetryCount, err = flags.GetUint16(flag.Name)
}
- })
+ })
if err != nil {
return err
}
diff --git a/cmd/root.go b/cmd/root.go
index 0d103b29..a20b2346 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -13,15 +13,13 @@ import (
"os"
"os/signal"
"path/filepath"
- "strings"
"syscall"
"time"
- homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
- v "github.com/spf13/viper"
+ "github.com/spf13/viper"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
"github.com/filebrowser/filebrowser/v2/auth"
@@ -35,28 +33,67 @@ import (
)
var (
- cfgFile string
+ flagNamesMigrations = map[string]string{
+ "file-mode": "fileMode",
+ "dir-mode": "dirMode",
+ "hide-login-button": "hideLoginButton",
+ "create-user-dir": "createUserDir",
+ "minimum-password-length": "minimumPasswordLength",
+ "socket-perm": "socketPerm",
+ "disable-thumbnails": "disableThumbnails",
+ "disable-preview-resize": "disablePreviewResize",
+ "disable-exec": "disableExec",
+ "disable-type-detection-by-header": "disableTypeDetectionByHeader",
+ "img-processors": "imageProcessors",
+ "cache-dir": "cacheDir",
+ "token-expiration-time": "tokenExpirationTime",
+ "baseurl": "baseURL",
+ }
+
+ warnedFlags = map[string]bool{}
)
+// TODO(remove): remove after July 2026.
+func migrateFlagNames(f *pflag.FlagSet, name string) pflag.NormalizedName {
+ if newName, ok := flagNamesMigrations[name]; ok {
+
+ if !warnedFlags[name] {
+ warnedFlags[name] = true
+ fmt.Printf("WARNING: Flag --%s has been deprecated, use --%s instead\n", name, newName)
+ }
+
+ name = newName
+ }
+
+ return pflag.NormalizedName(name)
+}
+
func init() {
- cobra.OnInitialize(initConfig)
rootCmd.SilenceUsage = true
+ rootCmd.SetGlobalNormalizationFunc(migrateFlagNames)
+
cobra.MousetrapHelpText = ""
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
- flags := rootCmd.Flags()
+ // Flags available across the whole program
persistent := rootCmd.PersistentFlags()
-
- persistent.StringVarP(&cfgFile, "config", "c", "", "config file path")
+ persistent.StringP("config", "c", "", "config file path")
persistent.StringP("database", "d", "./filebrowser.db", "database path")
- flags.Bool("noauth", false, "use the noauth auther when using quick setup")
- flags.String("username", "admin", "username for the first user when using quick config")
- flags.String("password", "", "hashed password for the first user when using quick config")
+ // Runtime flags for the root command
+ flags := rootCmd.Flags()
+ flags.Bool("noauth", false, "use the noauth auther when using quick setup")
+ flags.String("username", "admin", "username for the first user when using quick setup")
+ flags.String("password", "", "hashed password for the first user when using quick setup")
+ flags.Uint32("socketPerm", 0666, "unix socket file permissions")
+ flags.String("cacheDir", "", "file cache directory (disabled if empty)")
+ flags.Int("imageProcessors", 4, "image processors count")
addServerFlags(flags)
}
+// addServerFlags adds server related flags to the given FlagSet. These flags are available
+// in both the root command, config set and config init commands.
func addServerFlags(flags *pflag.FlagSet) {
flags.StringP("address", "a", "127.0.0.1", "address to listen on")
flags.StringP("log", "l", "stdout", "log output")
@@ -65,15 +102,12 @@ func addServerFlags(flags *pflag.FlagSet) {
flags.StringP("key", "k", "", "tls key")
flags.StringP("root", "r", ".", "root to prepend to relative paths")
flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)")
- flags.Uint32("socket-perm", 0666, "unix socket file permissions")
- flags.StringP("baseurl", "b", "", "base url")
- flags.String("cache-dir", "", "file cache directory (disabled if empty)")
- flags.String("token-expiration-time", "2h", "user session timeout")
- flags.Int("img-processors", 4, "image processors count")
- flags.Bool("disable-thumbnails", false, "disable image thumbnails")
- flags.Bool("disable-preview-resize", false, "disable resize of image previews")
- flags.Bool("disable-exec", true, "disables Command Runner feature")
- flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers")
+ flags.StringP("baseURL", "b", "", "base url")
+ flags.String("tokenExpirationTime", "2h", "user session timeout")
+ flags.Bool("disableThumbnails", false, "disable image thumbnails")
+ flags.Bool("disablePreviewResize", false, "disable resize of image previews")
+ flags.Bool("disableExec", true, "disables Command Runner feature")
+ flags.Bool("disableTypeDetectionByHeader", false, "disables type detection by reading file headers")
}
var rootCmd = &cobra.Command{
@@ -88,12 +122,14 @@ it. Don't worry: you don't need to setup a separate database server.
We're using Bolt DB which is a single file database and all managed
by ourselves.
-For this specific command, all the flags you have available (except
-"config" for the configuration file), can be given either through
-environment variables or configuration files.
+For this command, all flags are available as environmental variables,
+except for "--config", which specifies the configuration file to use.
+The environment variables are prefixed by "FB_" followed by the flag name in
+UPPER_SNAKE_CASE. For example, the flag "--disablePreviewResize" is available
+as FB_DISABLE_PREVIEW_RESIZE.
-If you don't set "config", it will look for a configuration file called
-.filebrowser.{json, toml, yaml, yml} in the following directories:
+If "--config" is not specified, File Browser will look for a configuration
+file named .filebrowser.{json, toml, yaml, yml} in the following directories:
- ./
- $HOME/
@@ -101,44 +137,32 @@ If you don't set "config", it will look for a configuration file called
The precedence of the configuration values are as follows:
-- flags
-- environment variables
-- configuration file
-- database values
-- defaults
-
-The environment variables are prefixed by "FB_" followed by the option
-name in caps. So to set "database" via an env variable, you should
-set FB_DATABASE.
+- Flags
+- Environment variables
+- Configuration file
+- Database values
+- Defaults
Also, if the database path doesn't exist, File Browser will enter into
the quick setup mode and a new database will be bootstrapped and a new
user created with the credentials from options "username" and "password".`,
RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
- log.Println(cfgFile)
-
- if !d.hadDB {
- err := quickSetup(cmd.Flags(), *d)
+ if !d.databaseExisted {
+ err := quickSetup(*d)
if err != nil {
return err
}
}
// build img service
- workersCount, err := cmd.Flags().GetInt("img-processors")
- if err != nil {
- return err
- }
- if workersCount < 1 {
+ imgWorkersCount := d.viper.GetInt("imageProcessors")
+ if imgWorkersCount < 1 {
return errors.New("image resize workers count could not be < 1")
}
- imgSvc := img.New(workersCount)
+ imageService := img.New(imgWorkersCount)
var fileCache diskcache.Interface = diskcache.NewNoOp()
- cacheDir, err := cmd.Flags().GetString("cache-dir")
- if err != nil {
- return err
- }
+ cacheDir := d.viper.GetString("cacheDir")
if cacheDir != "" {
if err := os.MkdirAll(cacheDir, 0700); err != nil {
return fmt.Errorf("can't make directory %s: %w", cacheDir, err)
@@ -146,7 +170,7 @@ user created with the credentials from options "username" and "password".`,
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
}
- server, err := getRunParams(cmd.Flags(), d.store)
+ server, err := getServerSettings(d.viper, d.store)
if err != nil {
return err
}
@@ -168,10 +192,7 @@ user created with the credentials from options "username" and "password".`,
if err != nil {
return err
}
- socketPerm, err := cmd.Flags().GetUint32("socket-perm")
- if err != nil {
- return err
- }
+ socketPerm := d.viper.GetUint32("socketPerm")
err = os.Chmod(server.Socket, os.FileMode(socketPerm))
if err != nil {
return err
@@ -200,7 +221,7 @@ user created with the credentials from options "username" and "password".`,
panic(err)
}
- handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, server, assetsFs)
+ handler, err := fbhttp.NewHandler(imageService, fileCache, d.store, server, assetsFs)
if err != nil {
return err
}
@@ -241,55 +262,59 @@ user created with the credentials from options "username" and "password".`,
log.Println("Graceful shutdown complete.")
return nil
- }, pythonConfig{allowNoDB: true}),
+ }, pythonConfig{allowsNoDatabase: true}),
}
-func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server, error) {
+func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, error) {
server, err := st.Settings.GetServer()
if err != nil {
return nil, err
}
- if val, set := getStringParamB(flags, "root"); set {
+ if val, set := vGetStringIsSet(v, "root"); set {
server.Root = val
}
- if val, set := getStringParamB(flags, "baseurl"); set {
+ if val, set := vGetStringIsSet(v, "baseURL"); set {
server.BaseURL = val
}
- if val, set := getStringParamB(flags, "log"); set {
+ if val, set := vGetStringIsSet(v, "log"); set {
server.Log = val
}
isSocketSet := false
isAddrSet := false
- if val, set := getStringParamB(flags, "address"); set {
+ if val, set := vGetStringIsSet(v, "address"); set {
server.Address = val
isAddrSet = isAddrSet || set
}
- if val, set := getStringParamB(flags, "port"); set {
+ if val, set := vGetStringIsSet(v, "port"); set {
server.Port = val
isAddrSet = isAddrSet || set
}
- if val, set := getStringParamB(flags, "key"); set {
+ if val, set := vGetStringIsSet(v, "key"); set {
server.TLSKey = val
isAddrSet = isAddrSet || set
}
- if val, set := getStringParamB(flags, "cert"); set {
+ if val, set := vGetStringIsSet(v, "cert"); set {
server.TLSCert = val
isAddrSet = isAddrSet || set
}
- if val, set := getStringParamB(flags, "socket"); set {
+ if val, set := vGetStringIsSet(v, "socket"); set {
server.Socket = val
isSocketSet = isSocketSet || set
}
+ if val, set := vGetStringIsSet(v, "tokenExpirationTime"); set {
+ server.TokenExpirationTime = val
+ }
+
if isAddrSet && isSocketSet {
return nil, errors.New("--socket flag cannot be used with --address, --port, --key nor --cert")
}
@@ -299,17 +324,10 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server,
server.Socket = ""
}
- disableThumbnails := getBoolParam(flags, "disable-thumbnails")
- server.EnableThumbnails = !disableThumbnails
-
- disablePreviewResize := getBoolParam(flags, "disable-preview-resize")
- server.ResizePreview = !disablePreviewResize
-
- disableTypeDetectionByHeader := getBoolParam(flags, "disable-type-detection-by-header")
- server.TypeDetectionByHeader = !disableTypeDetectionByHeader
-
- disableExec := getBoolParam(flags, "disable-exec")
- server.EnableExec = !disableExec
+ server.EnableThumbnails = !v.GetBool("disableThumbnails")
+ server.ResizePreview = !v.GetBool("disablePreviewResize")
+ server.TypeDetectionByHeader = !v.GetBool("disableTypeDetectionByHeader")
+ server.EnableExec = !v.GetBool("disableExec")
if server.EnableExec {
log.Println("WARNING: Command Runner feature enabled!")
@@ -318,69 +336,11 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) (*settings.Server,
log.Println("WARNING: read https://github.com/filebrowser/filebrowser/issues/5199")
}
- if val, set := getStringParamB(flags, "token-expiration-time"); set {
- server.TokenExpirationTime = val
- }
-
return server, nil
}
-// getBoolParamB returns a parameter as a string and a boolean to tell if it is different from the default
-//
-// NOTE: we could simply bind the flags to viper and use IsSet.
-// Although there is a bug on Viper that always returns true on IsSet
-// if a flag is binded. Our alternative way is to manually check
-// the flag and then the value from env/config/gotten by viper.
-// https://github.com/spf13/viper/pull/331
-func getBoolParamB(flags *pflag.FlagSet, key string) (value, ok bool) {
- value, _ = flags.GetBool(key)
-
- // If set on Flags, use it.
- if flags.Changed(key) {
- return value, true
- }
-
- // If set through viper (env, config), return it.
- if v.IsSet(key) {
- return v.GetBool(key), true
- }
-
- // Otherwise use default value on flags.
- return value, false
-}
-
-func getBoolParam(flags *pflag.FlagSet, key string) bool {
- val, _ := getBoolParamB(flags, key)
- return val
-}
-
-// getStringParamB returns a parameter as a string and a boolean to tell if it is different from the default
-//
-// NOTE: we could simply bind the flags to viper and use IsSet.
-// Although there is a bug on Viper that always returns true on IsSet
-// if a flag is binded. Our alternative way is to manually check
-// the flag and then the value from env/config/gotten by viper.
-// https://github.com/spf13/viper/pull/331
-func getStringParamB(flags *pflag.FlagSet, key string) (string, bool) {
- value, _ := flags.GetString(key)
-
- // If set on Flags, use it.
- if flags.Changed(key) {
- return value, true
- }
-
- // If set through viper (env, config), return it.
- if v.IsSet(key) {
- return v.GetString(key), true
- }
-
- // Otherwise use default value on flags.
- return value, false
-}
-
-func getStringParam(flags *pflag.FlagSet, key string) string {
- val, _ := getStringParamB(flags, key)
- return val
+func vGetStringIsSet(v *viper.Viper, key string) (string, bool) {
+ return v.GetString(key), v.IsSet(key)
}
func setupLog(logMethod string) {
@@ -401,7 +361,7 @@ func setupLog(logMethod string) {
}
}
-func quickSetup(flags *pflag.FlagSet, d pythonData) error {
+func quickSetup(d pythonData) error {
log.Println("Performing quick setup")
set := &settings.Settings{
@@ -415,7 +375,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error {
Scope: ".",
Locale: "en",
SingleClick: false,
- AceEditorTheme: getStringParam(flags, "defaults.aceEditorTheme"),
+ AceEditorTheme: d.viper.GetString("defaults.aceEditorTheme"),
Perm: users.Permissions{
Admin: false,
Execute: true,
@@ -439,7 +399,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error {
}
var err error
- if _, noauth := getStringParamB(flags, "noauth"); noauth {
+ if _, noauth := vGetStringIsSet(d.viper, "noauth"); noauth {
set.AuthMethod = auth.MethodNoAuth
err = d.store.Auth.Save(&auth.NoAuth{})
} else {
@@ -456,13 +416,13 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error {
}
ser := &settings.Server{
- BaseURL: getStringParam(flags, "baseurl"),
- Port: getStringParam(flags, "port"),
- Log: getStringParam(flags, "log"),
- TLSKey: getStringParam(flags, "key"),
- TLSCert: getStringParam(flags, "cert"),
- Address: getStringParam(flags, "address"),
- Root: getStringParam(flags, "root"),
+ BaseURL: d.viper.GetString("baseURL"),
+ Port: d.viper.GetString("port"),
+ Log: d.viper.GetString("log"),
+ TLSKey: d.viper.GetString("key"),
+ TLSCert: d.viper.GetString("cert"),
+ Address: d.viper.GetString("address"),
+ Root: d.viper.GetString("root"),
}
err = d.store.Settings.SaveServer(ser)
@@ -470,8 +430,8 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error {
return err
}
- username := getStringParam(flags, "username")
- password := getStringParam(flags, "password")
+ username := d.viper.GetString("username")
+ password := d.viper.GetString("password")
if password == "" {
var pwd string
@@ -504,32 +464,3 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) error {
return d.store.Users.Save(user)
}
-
-func initConfig() {
- if cfgFile == "" {
- home, err := homedir.Dir()
- if err != nil {
- panic(err)
- }
- v.AddConfigPath(".")
- v.AddConfigPath(home)
- v.AddConfigPath("/etc/filebrowser/")
- v.SetConfigName(".filebrowser")
- } else {
- v.SetConfigFile(cfgFile)
- }
-
- v.SetEnvPrefix("FB")
- v.AutomaticEnv()
- v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
-
- if err := v.ReadInConfig(); err != nil {
- var configParseError v.ConfigParseError
- if errors.As(err, &configParseError) {
- panic(err)
- }
- cfgFile = "No config file used"
- } else {
- cfgFile = "Using config file: " + v.ConfigFileUsed()
- }
-}
diff --git a/cmd/rules.go b/cmd/rules.go
index ffa5b1ae..bdb1d1cf 100644
--- a/cmd/rules.go
+++ b/cmd/rules.go
@@ -69,11 +69,12 @@ func runRules(st *storage.Storage, cmd *cobra.Command, usersFn func(*users.User)
}
func getUserIdentifier(flags *pflag.FlagSet) (interface{}, error) {
- id, err := getUint(flags, "id")
+ id, err := flags.GetUint("id")
if err != nil {
return nil, err
}
- username, err := getString(flags, "username")
+
+ username, err := flags.GetString("username")
if err != nil {
return nil, err
}
diff --git a/cmd/rules_add.go b/cmd/rules_add.go
index 9d1f0cf9..d58a6987 100644
--- a/cmd/rules_add.go
+++ b/cmd/rules_add.go
@@ -22,14 +22,18 @@ var rulesAddCmd = &cobra.Command{
Long: `Add a global rule or user rule.`,
Args: cobra.ExactArgs(1),
RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
- allow, err := getBool(cmd.Flags(), "allow")
+ flags := cmd.Flags()
+
+ allow, err := flags.GetBool("allow")
if err != nil {
return err
}
- regex, err := getBool(cmd.Flags(), "regex")
+
+ regex, err := flags.GetBool("regex")
if err != nil {
return err
}
+
exp := args[0]
if regex {
diff --git a/cmd/users.go b/cmd/users.go
index c2e2ce1e..86434a42 100644
--- a/cmd/users.go
+++ b/cmd/users.go
@@ -82,63 +82,64 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users")
}
-func getViewMode(flags *pflag.FlagSet) (users.ViewMode, error) {
- viewModeStr, err := getString(flags, "viewMode")
+func getAndParseViewMode(flags *pflag.FlagSet) (users.ViewMode, error) {
+ viewModeStr, err := flags.GetString("viewMode")
if err != nil {
return "", err
}
+
viewMode := users.ViewMode(viewModeStr)
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
return "", errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\"")
}
+
return viewMode, nil
}
func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all bool) error {
- var visitErr error
+ errs := []error{}
+
visit := func(flag *pflag.Flag) {
- if visitErr != nil {
- return
- }
var err error
switch flag.Name {
case "scope":
- defaults.Scope, err = getString(flags, flag.Name)
+ defaults.Scope, err = flags.GetString(flag.Name)
case "locale":
- defaults.Locale, err = getString(flags, flag.Name)
+ defaults.Locale, err = flags.GetString(flag.Name)
case "viewMode":
- defaults.ViewMode, err = getViewMode(flags)
+ defaults.ViewMode, err = getAndParseViewMode(flags)
case "singleClick":
- defaults.SingleClick, err = getBool(flags, flag.Name)
+ defaults.SingleClick, err = flags.GetBool(flag.Name)
case "aceEditorTheme":
- defaults.AceEditorTheme, err = getString(flags, flag.Name)
+ defaults.AceEditorTheme, err = flags.GetString(flag.Name)
case "perm.admin":
- defaults.Perm.Admin, err = getBool(flags, flag.Name)
+ defaults.Perm.Admin, err = flags.GetBool(flag.Name)
case "perm.execute":
- defaults.Perm.Execute, err = getBool(flags, flag.Name)
+ defaults.Perm.Execute, err = flags.GetBool(flag.Name)
case "perm.create":
- defaults.Perm.Create, err = getBool(flags, flag.Name)
+ defaults.Perm.Create, err = flags.GetBool(flag.Name)
case "perm.rename":
- defaults.Perm.Rename, err = getBool(flags, flag.Name)
+ defaults.Perm.Rename, err = flags.GetBool(flag.Name)
case "perm.modify":
- defaults.Perm.Modify, err = getBool(flags, flag.Name)
+ defaults.Perm.Modify, err = flags.GetBool(flag.Name)
case "perm.delete":
- defaults.Perm.Delete, err = getBool(flags, flag.Name)
+ defaults.Perm.Delete, err = flags.GetBool(flag.Name)
case "perm.share":
- defaults.Perm.Share, err = getBool(flags, flag.Name)
+ defaults.Perm.Share, err = flags.GetBool(flag.Name)
case "perm.download":
- defaults.Perm.Download, err = getBool(flags, flag.Name)
+ defaults.Perm.Download, err = flags.GetBool(flag.Name)
case "commands":
defaults.Commands, err = flags.GetStringSlice(flag.Name)
case "sorting.by":
- defaults.Sorting.By, err = getString(flags, flag.Name)
+ defaults.Sorting.By, err = flags.GetString(flag.Name)
case "sorting.asc":
- defaults.Sorting.Asc, err = getBool(flags, flag.Name)
+ defaults.Sorting.Asc, err = flags.GetBool(flag.Name)
case "hideDotfiles":
- defaults.HideDotfiles, err = getBool(flags, flag.Name)
+ defaults.HideDotfiles, err = flags.GetBool(flag.Name)
}
+
if err != nil {
- visitErr = err
+ errs = append(errs, err)
}
}
@@ -147,5 +148,6 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
} else {
flags.Visit(visit)
}
- return visitErr
+
+ return errors.Join(errs...)
}
diff --git a/cmd/users_add.go b/cmd/users_add.go
index dce7ff98..bfc70069 100644
--- a/cmd/users_add.go
+++ b/cmd/users_add.go
@@ -17,11 +17,12 @@ var usersAddCmd = &cobra.Command{
Long: `Create a new user and add it to the database.`,
Args: cobra.ExactArgs(2),
RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ flags := cmd.Flags()
s, err := d.store.Settings.Get()
if err != nil {
return err
}
- err = getUserDefaults(cmd.Flags(), &s.Defaults, false)
+ err = getUserDefaults(flags, &s.Defaults, false)
if err != nil {
return err
}
@@ -31,27 +32,24 @@ var usersAddCmd = &cobra.Command{
return err
}
- lockPassword, err := getBool(cmd.Flags(), "lockPassword")
- if err != nil {
- return err
- }
-
- dateFormat, err := getBool(cmd.Flags(), "dateFormat")
- if err != nil {
- return err
- }
-
- hideDotfiles, err := getBool(cmd.Flags(), "hideDotfiles")
- if err != nil {
- return err
- }
-
user := &users.User{
- Username: args[0],
- Password: password,
- LockPassword: lockPassword,
- DateFormat: dateFormat,
- HideDotfiles: hideDotfiles,
+ Username: args[0],
+ Password: password,
+ }
+
+ user.LockPassword, err = flags.GetBool("lockPassword")
+ if err != nil {
+ return err
+ }
+
+ user.DateFormat, err = flags.GetBool("dateFormat")
+ if err != nil {
+ return err
+ }
+
+ user.HideDotfiles, err = flags.GetBool("hideDotfiles")
+ if err != nil {
+ return err
}
s.Defaults.Apply(user)
diff --git a/cmd/users_import.go b/cmd/users_import.go
index 74353c2c..d08889df 100644
--- a/cmd/users_import.go
+++ b/cmd/users_import.go
@@ -26,6 +26,7 @@ installation. For that, just don't place their ID on the files
list or set it to 0.`,
Args: jsonYamlArg,
RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ flags := cmd.Flags()
fd, err := os.Open(args[0])
if err != nil {
return err
@@ -45,7 +46,7 @@ list or set it to 0.`,
}
}
- replace, err := getBool(cmd.Flags(), "replace")
+ replace, err := flags.GetBool("replace")
if err != nil {
return err
}
@@ -69,7 +70,7 @@ list or set it to 0.`,
}
}
- overwrite, err := getBool(cmd.Flags(), "overwrite")
+ overwrite, err := flags.GetBool("overwrite")
if err != nil {
return err
}
diff --git a/cmd/users_update.go b/cmd/users_update.go
index a939e605..59854a81 100644
--- a/cmd/users_update.go
+++ b/cmd/users_update.go
@@ -22,13 +22,14 @@ var usersUpdateCmd = &cobra.Command{
options you want to change.`,
Args: cobra.ExactArgs(1),
RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
- username, id := parseUsernameOrID(args[0])
flags := cmd.Flags()
- password, err := getString(flags, "password")
+ username, id := parseUsernameOrID(args[0])
+ password, err := flags.GetString("password")
if err != nil {
return err
}
- newUsername, err := getString(flags, "username")
+
+ newUsername, err := flags.GetString("username")
if err != nil {
return err
}
@@ -41,13 +42,11 @@ options you want to change.`,
var (
user *users.User
)
-
if id != 0 {
user, err = d.store.Users.Get("", id)
} else {
user, err = d.store.Users.Get("", username)
}
-
if err != nil {
return err
}
@@ -61,10 +60,12 @@ options you want to change.`,
Sorting: user.Sorting,
Commands: user.Commands,
}
+
err = getUserDefaults(flags, &defaults, false)
if err != nil {
return err
}
+
user.Scope = defaults.Scope
user.Locale = defaults.Locale
user.ViewMode = defaults.ViewMode
@@ -72,15 +73,17 @@ options you want to change.`,
user.Perm = defaults.Perm
user.Commands = defaults.Commands
user.Sorting = defaults.Sorting
- user.LockPassword, err = getBool(flags, "lockPassword")
+ user.LockPassword, err = flags.GetBool("lockPassword")
if err != nil {
return err
}
- user.DateFormat, err = getBool(flags, "dateFormat")
+
+ user.DateFormat, err = flags.GetBool("dateFormat")
if err != nil {
return err
}
- user.HideDotfiles, err = getBool(flags, "hideDotfiles")
+
+ user.HideDotfiles, err = flags.GetBool("hideDotfiles")
if err != nil {
return err
}
diff --git a/cmd/utils.go b/cmd/utils.go
index 3ed5c989..a136db10 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -12,8 +12,11 @@ import (
"strings"
"github.com/asdine/storm/v3"
+ homedir "github.com/mitchellh/go-homedir"
+ "github.com/samber/lo"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
+ "github.com/spf13/viper"
yaml "gopkg.in/yaml.v3"
"github.com/filebrowser/filebrowser/v2/settings"
@@ -21,32 +24,21 @@ import (
"github.com/filebrowser/filebrowser/v2/storage/bolt"
)
-const dbPerms = 0640
+const databasePermissions = 0640
-func getString(flags *pflag.FlagSet, flag string) (string, error) {
- return flags.GetString(flag)
-}
-
-func getMode(flags *pflag.FlagSet, flag string) (fs.FileMode, error) {
- s, err := getString(flags, flag)
+func getAndParseFileMode(flags *pflag.FlagSet, name string) (fs.FileMode, error) {
+ mode, err := flags.GetString(name)
if err != nil {
return 0, err
}
- b, err := strconv.ParseUint(s, 0, 32)
+
+ b, err := strconv.ParseUint(mode, 0, 32)
if err != nil {
return 0, err
}
return fs.FileMode(b), nil
}
-func getBool(flags *pflag.FlagSet, flag string) (bool, error) {
- return flags.GetBool(flag)
-}
-
-func getUint(flags *pflag.FlagSet, flag string) (uint, error) {
- return flags.GetUint(flag)
-}
-
func generateKey() []byte {
k, err := settings.GenerateKey()
if err != nil {
@@ -55,19 +47,6 @@ func generateKey() []byte {
return k
}
-type cobraFunc func(cmd *cobra.Command, args []string) error
-type pythonFunc func(cmd *cobra.Command, args []string, data *pythonData) error
-
-type pythonConfig struct {
- noDB bool
- allowNoDB bool
-}
-
-type pythonData struct {
- hadDB bool
- store *storage.Storage
-}
-
func dbExists(path string) (bool, error) {
stat, err := os.Stat(path)
if err == nil {
@@ -88,38 +67,131 @@ func dbExists(path string) (bool, error) {
return false, err
}
+// Generate the replacements for all environment variables. This allows to
+// use FB_BRANDING_DISABLE_EXTERNAL environment variables, even when the
+// option name is branding.disableExternal.
+func generateEnvKeyReplacements(cmd *cobra.Command) []string {
+ replacements := []string{}
+
+ cmd.Flags().VisitAll(func(f *pflag.Flag) {
+ oldName := strings.ToUpper(f.Name)
+ newName := strings.ToUpper(lo.SnakeCase(f.Name))
+ replacements = append(replacements, oldName, newName)
+ })
+
+ return replacements
+}
+
+func initViper(cmd *cobra.Command) (*viper.Viper, error) {
+ v := viper.New()
+
+ // Get config file from flag
+ cfgFile, err := cmd.Flags().GetString("config")
+ if err != nil {
+ return nil, err
+ }
+
+ // Configuration file
+ if cfgFile == "" {
+ home, err := homedir.Dir()
+ if err != nil {
+ return nil, err
+ }
+ v.AddConfigPath(".")
+ v.AddConfigPath(home)
+ v.AddConfigPath("/etc/filebrowser/")
+ v.SetConfigName(".filebrowser")
+ } else {
+ v.SetConfigFile(cfgFile)
+ }
+
+ // Environment variables
+ v.SetEnvPrefix("FB")
+ v.AutomaticEnv()
+ v.SetEnvKeyReplacer(strings.NewReplacer(generateEnvKeyReplacements(cmd)...))
+
+ // Bind the flags
+ err = v.BindPFlags(cmd.Flags())
+ if err != nil {
+ return nil, err
+ }
+
+ // Read in configuration
+ if err := v.ReadInConfig(); err != nil {
+ if errors.Is(err, viper.ConfigParseError{}) {
+ return nil, err
+ }
+
+ log.Println("No config file used")
+ } else {
+ log.Printf("Using config file: %s", v.ConfigFileUsed())
+ }
+
+ // Return Viper
+ return v, nil
+}
+
+type cobraFunc func(cmd *cobra.Command, args []string) error
+type pythonFunc func(cmd *cobra.Command, args []string, data *pythonData) error
+
+type pythonConfig struct {
+ expectsNoDatabase bool
+ allowsNoDatabase bool
+}
+
+type pythonData struct {
+ databaseExisted bool
+ viper *viper.Viper
+ store *storage.Storage
+}
+
func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
return func(cmd *cobra.Command, args []string) error {
- data := &pythonData{hadDB: true}
+ v, err := initViper(cmd)
+ if err != nil {
+ return err
+ }
+
+ data := &pythonData{databaseExisted: true}
+ path := v.GetString("database")
+
+ // Only make the viper instance available to the root command (filebrowser).
+ // This is to make sure that we don't make the mistake of using it somewhere
+ // else.
+ if cmd.Name() == "filebrowser" {
+ data.viper = v
+ }
- path := getStringParam(cmd.Flags(), "database")
absPath, err := filepath.Abs(path)
if err != nil {
- panic(err)
+ return err
}
- exists, err := dbExists(path)
+ exists, err := dbExists(path)
if err != nil {
- panic(err)
- } else if exists && cfg.noDB {
+ return err
+ } else if exists && cfg.expectsNoDatabase {
log.Fatal(absPath + " already exists")
- } else if !exists && !cfg.noDB && !cfg.allowNoDB {
+ } else if !exists && !cfg.expectsNoDatabase && !cfg.allowsNoDatabase {
log.Fatal(absPath + " does not exist. Please run 'filebrowser config init' first.")
- } else if !exists && !cfg.noDB {
+ } else if !exists && !cfg.expectsNoDatabase {
log.Println("Warning: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(absPath, "filebrowser.db"))
}
log.Println("Using database: " + absPath)
- data.hadDB = exists
- db, err := storm.Open(path, storm.BoltOptions(dbPerms, nil))
+ data.databaseExisted = exists
+
+ db, err := storm.Open(path, storm.BoltOptions(databasePermissions, nil))
if err != nil {
return err
}
defer db.Close()
+
data.store, err = bolt.NewStorage(db)
if err != nil {
return err
}
+
return fn(cmd, args, data)
}
}
diff --git a/go.mod b/go.mod
index 47da2619..abaeff87 100644
--- a/go.mod
+++ b/go.mod
@@ -16,6 +16,7 @@ require (
github.com/marusama/semaphore/v2 v2.5.0
github.com/mholt/archives v0.1.5
github.com/mitchellh/go-homedir v1.1.0
+ github.com/samber/lo v1.52.0
github.com/shirou/gopsutil/v4 v4.25.10
github.com/spf13/afero v1.15.0
github.com/spf13/cobra v1.10.1
diff --git a/go.sum b/go.sum
index c6b0e41b..551f034e 100644
--- a/go.sum
+++ b/go.sum
@@ -202,6 +202,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
+github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
+github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA=
github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM=
github.com/sorairolake/lzip-go v0.3.8 h1:j5Q2313INdTA80ureWYRhX+1K78mUXfMoPZCw/ivWik=
From 8c5dc7641e6f8aadd9e5d5d3b25a2ad9f1ec9a1e Mon Sep 17 00:00:00 2001
From: Brian Fromm <69060375+brianfromm@users.noreply.github.com>
Date: Mon, 17 Nov 2025 00:57:02 -0700
Subject: [PATCH 026/120] fix: add tokenExpirationTime to `config init` and
troubleshoot docs (#5546)
Co-authored-by: Henrique Dias
---
cmd/config.go | 1 +
cmd/config_init.go | 5 +++++
docker/common/defaults/settings.json | 2 +-
www/docs/troubleshooting.md | 9 +++++++++
www/mkdocs.yml | 1 +
5 files changed, 17 insertions(+), 1 deletion(-)
create mode 100644 www/docs/troubleshooting.md
diff --git a/cmd/config.go b/cmd/config.go
index 73d4faa9..8dc8baa7 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -222,6 +222,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
+ fmt.Fprintf(w, "\tToken Expiration Time:\t%s\n", ser.TokenExpirationTime)
fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
fmt.Fprintf(w, "\tThumbnails Enabled:\t%t\n", ser.EnableThumbnails)
fmt.Fprintf(w, "\tResize Preview:\t%t\n", ser.ResizePreview)
diff --git a/cmd/config_init.go b/cmd/config_init.go
index 21cacb33..4c9aab63 100644
--- a/cmd/config_init.go
+++ b/cmd/config_init.go
@@ -155,6 +155,11 @@ override the options.`,
return err
}
+ ser.TokenExpirationTime, err = flags.GetString("tokenExpirationTime")
+ if err != nil {
+ return err
+ }
+
err = d.store.Settings.Save(s)
if err != nil {
return err
diff --git a/docker/common/defaults/settings.json b/docker/common/defaults/settings.json
index e787ef87..cf7fb4ee 100644
--- a/docker/common/defaults/settings.json
+++ b/docker/common/defaults/settings.json
@@ -5,4 +5,4 @@
"log": "stdout",
"database": "/database/filebrowser.db",
"root": "/srv"
-}
\ No newline at end of file
+}
diff --git a/www/docs/troubleshooting.md b/www/docs/troubleshooting.md
new file mode 100644
index 00000000..a994957e
--- /dev/null
+++ b/www/docs/troubleshooting.md
@@ -0,0 +1,9 @@
+# Troubleshooting
+
+## Session Timeout
+
+By default, user sessions expire after **2 hours**. If you're uploading large files over slower connections, you may need to increase this timeout to prevent sessions from expiring mid-upload. You can configure the session timeout using the `tokenExpirationTime` setting.
+
+You can either set this option during runtime by using the flag `--tokenExpirationTime`, the environment variable `FB_TOKEN_EXPIRATION_TIME`, or in your configuration file. If you want to persist this to the configuration, please use [`filebrowser config set`](cli/filebrowser-config-set.md).
+
+Valid duration formats include `"2h"`, `"30m"`, `"24h"`, or combinations like `"2h30m"`.
diff --git a/www/mkdocs.yml b/www/mkdocs.yml
index 7558c534..c71c6798 100644
--- a/www/mkdocs.yml
+++ b/www/mkdocs.yml
@@ -100,6 +100,7 @@ nav:
- customization.md
- authentication.md
- command-execution.md
+ - Troubleshooting: troubleshooting.md
- Deployment: deployment.md
- Command Line Usage:
- cli/filebrowser.md
From 89be0b1873527987dd2dddac746e93b8bc684d46 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 09:16:54 +0100
Subject: [PATCH 027/120] refactor: reuse logic for config init and set
---
cmd/config.go | 125 +++++++++++++++++++++++++++++++++++++++--
cmd/config_init.go | 136 ++-------------------------------------------
cmd/config_set.go | 100 ++-------------------------------
3 files changed, 132 insertions(+), 229 deletions(-)
diff --git a/cmd/config.go b/cmd/config.go
index 8dc8baa7..7f9b1c19 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -37,6 +37,11 @@ func addConfigFlags(flags *pflag.FlagSet) {
flags.Uint("minimumPasswordLength", settings.DefaultMinimumPasswordLength, "minimum password length for new users")
flags.String("shell", "", "shell command to which other commands should be appended")
+ // NB: these are string so they can be presented as octal in the help text
+ // as that's the conventional representation for modes in Unix.
+ flags.String("fileMode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with")
+ flags.String("dirMode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with")
+
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
flags.String("auth.header", "", "HTTP header for auth.method=proxy")
flags.String("auth.command", "", "command for auth.method=hook")
@@ -52,11 +57,6 @@ func addConfigFlags(flags *pflag.FlagSet) {
flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
- // NB: these are string so they can be presented as octal in the help text
- // as that's the conventional representation for modes in Unix.
- flags.String("fileMode", fmt.Sprintf("%O", settings.DefaultFileMode), "mode bits that new files are created with")
- flags.String("dirMode", fmt.Sprintf("%O", settings.DefaultDirMode), "mode bits that new directories are created with")
-
flags.Uint64("tus.chunkSize", settings.DefaultTusChunkSize, "the tus chunk size")
flags.Uint16("tus.retryCount", settings.DefaultTusRetryCount, "the tus retry count")
}
@@ -266,3 +266,118 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
return nil
}
+
+func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Server, auther auth.Auther, all bool) (auth.Auther, error) {
+ errs := []error{}
+ hasAuth := false
+
+ visit := func(flag *pflag.Flag) {
+ var err error
+
+ switch flag.Name {
+ // Server flags from [addServerFlags]
+ case "address":
+ ser.Address, err = flags.GetString(flag.Name)
+ case "log":
+ ser.Log, err = flags.GetString(flag.Name)
+ case "port":
+ ser.Port, err = flags.GetString(flag.Name)
+ case "cert":
+ ser.TLSCert, err = flags.GetString(flag.Name)
+ case "key":
+ ser.TLSKey, err = flags.GetString(flag.Name)
+ case "root":
+ ser.Root, err = flags.GetString(flag.Name)
+ case "socket":
+ ser.Socket, err = flags.GetString(flag.Name)
+ case "baseURL":
+ ser.BaseURL, err = flags.GetString(flag.Name)
+ case "tokenExpirationTime":
+ ser.TokenExpirationTime, err = flags.GetString(flag.Name)
+ case "disableThumbnails":
+ ser.EnableThumbnails, err = flags.GetBool(flag.Name)
+ ser.EnableThumbnails = !ser.EnableThumbnails
+ case "disablePreviewResize":
+ ser.ResizePreview, err = flags.GetBool(flag.Name)
+ ser.ResizePreview = !ser.ResizePreview
+ case "disableExec":
+ ser.EnableExec, err = flags.GetBool(flag.Name)
+ ser.EnableExec = !ser.EnableExec
+ case "disableTypeDetectionByHeader":
+ ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name)
+ ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader
+
+ // Settings flags from [addConfigFlags]
+ case "signup":
+ set.Signup, err = flags.GetBool(flag.Name)
+ case "hideLoginButton":
+ set.HideLoginButton, err = flags.GetBool(flag.Name)
+ case "createUserDir":
+ set.CreateUserDir, err = flags.GetBool(flag.Name)
+ case "minimumPasswordLength":
+ set.MinimumPasswordLength, err = flags.GetUint(flag.Name)
+ case "shell":
+ var shell string
+ shell, err = flags.GetString(flag.Name)
+ if err == nil {
+ set.Shell = convertCmdStrToCmdArray(shell)
+ }
+ case "auth.method":
+ hasAuth = true
+ case "branding.name":
+ set.Branding.Name, err = flags.GetString(flag.Name)
+ case "branding.theme":
+ set.Branding.Theme, err = flags.GetString(flag.Name)
+ case "branding.color":
+ set.Branding.Color, err = flags.GetString(flag.Name)
+ case "branding.files":
+ set.Branding.Files, err = flags.GetString(flag.Name)
+ case "branding.disableExternal":
+ set.Branding.DisableExternal, err = flags.GetBool(flag.Name)
+ case "branding.disableUsedPercentage":
+ set.Branding.DisableUsedPercentage, err = flags.GetBool(flag.Name)
+ case "fileMode":
+ set.FileMode, err = getAndParseFileMode(flags, flag.Name)
+ case "dirMode":
+ set.DirMode, err = getAndParseFileMode(flags, flag.Name)
+ case "tus.chunkSize":
+ set.Tus.ChunkSize, err = flags.GetUint64(flag.Name)
+ case "tus.retryCount":
+ set.Tus.RetryCount, err = flags.GetUint16(flag.Name)
+ }
+
+ if err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ if all {
+ flags.VisitAll(visit)
+ } else {
+ flags.Visit(visit)
+ }
+
+ err := nerrors.Join(errs...)
+ if err != nil {
+ return nil, err
+ }
+
+ err = getUserDefaults(flags, &set.Defaults, all)
+ if err != nil {
+ return nil, err
+ }
+
+ if all {
+ set.AuthMethod, auther, err = getAuthentication(flags)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ set.AuthMethod, auther, err = getAuthentication(flags, hasAuth, set, auther)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return auther, nil
+}
diff --git a/cmd/config_init.go b/cmd/config_init.go
index 4c9aab63..2787f080 100644
--- a/cmd/config_init.go
+++ b/cmd/config_init.go
@@ -5,7 +5,6 @@ import (
"github.com/spf13/cobra"
- "github.com/filebrowser/filebrowser/v2/auth"
"github.com/filebrowser/filebrowser/v2/settings"
)
@@ -26,140 +25,17 @@ override the options.`,
RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
flags := cmd.Flags()
- // General Settings
- s := &settings.Settings{
- Key: generateKey(),
- }
-
- err := getUserDefaults(flags, &s.Defaults, true)
- if err != nil {
- return err
- }
-
- s.Signup, err = flags.GetBool("signup")
- if err != nil {
- return err
- }
-
- s.HideLoginButton, err = flags.GetBool("hideLoginButton")
- if err != nil {
- return err
- }
-
- s.CreateUserDir, err = flags.GetBool("createUserDir")
- if err != nil {
- return err
- }
-
- s.MinimumPasswordLength, err = flags.GetUint("minimumPasswordLength")
- if err != nil {
- return err
- }
-
- shell, err := flags.GetString("shell")
- if err != nil {
- return err
- }
- s.Shell = convertCmdStrToCmdArray(shell)
-
- s.FileMode, err = getAndParseFileMode(flags, "fileMode")
- if err != nil {
- return err
- }
-
- s.DirMode, err = getAndParseFileMode(flags, "dirMode")
- if err != nil {
- return err
- }
-
- s.Branding.Name, err = flags.GetString("branding.name")
- if err != nil {
- return err
- }
-
- s.Branding.DisableExternal, err = flags.GetBool("branding.disableExternal")
- if err != nil {
- return err
- }
-
- s.Branding.DisableUsedPercentage, err = flags.GetBool("branding.disableUsedPercentage")
- if err != nil {
- return err
- }
-
- s.Branding.Theme, err = flags.GetString("branding.themes")
- if err != nil {
- return err
- }
-
- s.Branding.Files, err = flags.GetString("branding.files")
- if err != nil {
- return err
- }
-
- s.Tus.ChunkSize, err = flags.GetUint64("tus.chunkSize")
- if err != nil {
- return err
- }
-
- s.Tus.RetryCount, err = flags.GetUint16("tus.retryCount")
- if err != nil {
- return err
- }
-
- var auther auth.Auther
- s.AuthMethod, auther, err = getAuthentication(flags)
- if err != nil {
- return err
- }
-
- // Server Settings
+ // Initialize config
+ s := &settings.Settings{Key: generateKey()}
ser := &settings.Server{}
- ser.Address, err = flags.GetString("address")
- if err != nil {
- return err
- }
-
- ser.Socket, err = flags.GetString("socket")
- if err != nil {
- return err
- }
-
- ser.Root, err = flags.GetString("root")
- if err != nil {
- return err
- }
-
- ser.BaseURL, err = flags.GetString("baseURL")
- if err != nil {
- return err
- }
-
- ser.TLSKey, err = flags.GetString("key")
- if err != nil {
- return err
- }
-
- ser.TLSCert, err = flags.GetString("cert")
- if err != nil {
- return err
- }
-
- ser.Port, err = flags.GetString("port")
- if err != nil {
- return err
- }
-
- ser.Log, err = flags.GetString("log")
- if err != nil {
- return err
- }
-
- ser.TokenExpirationTime, err = flags.GetString("tokenExpirationTime")
+
+ // Fill config with options
+ auther, err := getSettings(flags, s, ser, nil, true)
if err != nil {
return err
}
+ // Save updated config
err = d.store.Settings.Save(s)
if err != nil {
return err
diff --git a/cmd/config_set.go b/cmd/config_set.go
index 74fae9ea..d25b6596 100644
--- a/cmd/config_set.go
+++ b/cmd/config_set.go
@@ -2,7 +2,6 @@ package cmd
import (
"github.com/spf13/cobra"
- "github.com/spf13/pflag"
)
func init() {
@@ -19,6 +18,7 @@ you want to change. Other options will remain unchanged.`,
RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
flags := cmd.Flags()
+ // Read existing config
set, err := d.store.Settings.Get()
if err != nil {
return err
@@ -29,116 +29,28 @@ you want to change. Other options will remain unchanged.`,
return err
}
- hasAuth := false
-
- flags.Visit(func(flag *pflag.Flag) {
- if err != nil {
- return
- }
-
- switch flag.Name {
- // Server flags from [addServerFlags]
- case "address":
- ser.Address, err = flags.GetString(flag.Name)
- case "log":
- ser.Log, err = flags.GetString(flag.Name)
- case "port":
- ser.Port, err = flags.GetString(flag.Name)
- case "cert":
- ser.TLSCert, err = flags.GetString(flag.Name)
- case "key":
- ser.TLSKey, err = flags.GetString(flag.Name)
- case "root":
- ser.Root, err = flags.GetString(flag.Name)
- case "socket":
- ser.Socket, err = flags.GetString(flag.Name)
- case "baseURL":
- ser.BaseURL, err = flags.GetString(flag.Name)
- case "tokenExpirationTime":
- ser.TokenExpirationTime, err = flags.GetString(flag.Name)
- case "disableThumbnails":
- ser.EnableThumbnails, err = flags.GetBool(flag.Name)
- ser.EnableThumbnails = !ser.EnableThumbnails
- case "disablePreviewResize":
- ser.ResizePreview, err = flags.GetBool(flag.Name)
- ser.ResizePreview = !ser.ResizePreview
- case "disableExec":
- ser.EnableExec, err = flags.GetBool(flag.Name)
- ser.EnableExec = !ser.EnableExec
- case "disableTypeDetectionByHeader":
- ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name)
- ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader
-
- // Settings flags from [addConfigFlags]
- case "signup":
- set.Signup, err = flags.GetBool(flag.Name)
- case "hideLoginButton":
- set.HideLoginButton, err = flags.GetBool(flag.Name)
- case "createUserDir":
- set.CreateUserDir, err = flags.GetBool(flag.Name)
- case "minimumPasswordLength":
- set.MinimumPasswordLength, err = flags.GetUint(flag.Name)
- case "shell":
- var shell string
- shell, err = flags.GetString(flag.Name)
- if err != nil {
- return
- }
- set.Shell = convertCmdStrToCmdArray(shell)
- case "auth.method":
- hasAuth = true
- case "branding.name":
- set.Branding.Name, err = flags.GetString(flag.Name)
- case "branding.theme":
- set.Branding.Theme, err = flags.GetString(flag.Name)
- case "branding.color":
- set.Branding.Color, err = flags.GetString(flag.Name)
- case "branding.files":
- set.Branding.Files, err = flags.GetString(flag.Name)
- case "branding.disableExternal":
- set.Branding.DisableExternal, err = flags.GetBool(flag.Name)
- case "branding.disableUsedPercentage":
- set.Branding.DisableUsedPercentage, err = flags.GetBool(flag.Name)
- case "fileMode":
- set.FileMode, err = getAndParseFileMode(flags, flag.Name)
- case "dirMode":
- set.DirMode, err = getAndParseFileMode(flags, flag.Name)
- case "tus.chunkSize":
- set.Tus.ChunkSize, err = flags.GetUint64(flag.Name)
- case "tus.retryCount":
- set.Tus.RetryCount, err = flags.GetUint16(flag.Name)
- }
-
- })
- if err != nil {
- return err
- }
-
- err = getUserDefaults(flags, &set.Defaults, false)
- if err != nil {
- return err
- }
-
- // read the defaults
auther, err := d.store.Auth.Get(set.AuthMethod)
if err != nil {
return err
}
- // check if there are new flags for existing auth method
- set.AuthMethod, auther, err = getAuthentication(flags, hasAuth, set, auther)
+ // Get updated config
+ auther, err = getSettings(flags, set, ser, auther, false)
if err != nil {
return err
}
+ // Save updated config
err = d.store.Auth.Save(auther)
if err != nil {
return err
}
+
err = d.store.Settings.Save(set)
if err != nil {
return err
}
+
err = d.store.Settings.SaveServer(ser)
if err != nil {
return err
From f41585f0392d65c08c01ab65b62d3eeb04c03b7d Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 09:17:30 +0100
Subject: [PATCH 028/120] fix: use all available flags in quick setup
---
cmd/config.go | 10 +++++-----
cmd/root.go | 19 ++++++++++++-------
2 files changed, 17 insertions(+), 12 deletions(-)
diff --git a/cmd/config.go b/cmd/config.go
index 7f9b1c19..550ab5c9 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -307,7 +307,7 @@ func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Ser
ser.TypeDetectionByHeader, err = flags.GetBool(flag.Name)
ser.TypeDetectionByHeader = !ser.TypeDetectionByHeader
- // Settings flags from [addConfigFlags]
+ // Settings flags from [addConfigFlags]
case "signup":
set.Signup, err = flags.GetBool(flag.Name)
case "hideLoginButton":
@@ -322,6 +322,10 @@ func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Ser
if err == nil {
set.Shell = convertCmdStrToCmdArray(shell)
}
+ case "fileMode":
+ set.FileMode, err = getAndParseFileMode(flags, flag.Name)
+ case "dirMode":
+ set.DirMode, err = getAndParseFileMode(flags, flag.Name)
case "auth.method":
hasAuth = true
case "branding.name":
@@ -336,10 +340,6 @@ func getSettings(flags *pflag.FlagSet, set *settings.Settings, ser *settings.Ser
set.Branding.DisableExternal, err = flags.GetBool(flag.Name)
case "branding.disableUsedPercentage":
set.Branding.DisableUsedPercentage, err = flags.GetBool(flag.Name)
- case "fileMode":
- set.FileMode, err = getAndParseFileMode(flags, flag.Name)
- case "dirMode":
- set.DirMode, err = getAndParseFileMode(flags, flag.Name)
case "tus.chunkSize":
set.Tus.ChunkSize, err = flags.GetUint64(flag.Name)
case "tus.retryCount":
diff --git a/cmd/root.go b/cmd/root.go
index a20b2346..668d06ef 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -416,13 +416,18 @@ func quickSetup(d pythonData) error {
}
ser := &settings.Server{
- BaseURL: d.viper.GetString("baseURL"),
- Port: d.viper.GetString("port"),
- Log: d.viper.GetString("log"),
- TLSKey: d.viper.GetString("key"),
- TLSCert: d.viper.GetString("cert"),
- Address: d.viper.GetString("address"),
- Root: d.viper.GetString("root"),
+ BaseURL: d.viper.GetString("baseURL"),
+ Port: d.viper.GetString("port"),
+ Log: d.viper.GetString("log"),
+ TLSKey: d.viper.GetString("key"),
+ TLSCert: d.viper.GetString("cert"),
+ Address: d.viper.GetString("address"),
+ Root: d.viper.GetString("root"),
+ TokenExpirationTime: d.viper.GetString("tokenExpirationTime"),
+ EnableThumbnails: !d.viper.GetBool("disableThumbnails"),
+ ResizePreview: !d.viper.GetBool("disablePreviewResize"),
+ EnableExec: !d.viper.GetBool("disableExec"),
+ TypeDetectionByHeader: !d.viper.GetBool("disableTypeDetectionByHeader"),
}
err = d.store.Settings.SaveServer(ser)
From 9bdc67c2071f38fce4cd481c7a7b8ea5d3eaa3ab Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 09:38:45 +0100
Subject: [PATCH 029/120] chore(docs): update CLI documentation
---
www/docs/cli/filebrowser-config-init.md | 111 ++++++++++++------------
www/docs/cli/filebrowser-config-set.md | 111 ++++++++++++------------
www/docs/cli/filebrowser.md | 70 ++++++++-------
3 files changed, 142 insertions(+), 150 deletions(-)
diff --git a/www/docs/cli/filebrowser-config-init.md b/www/docs/cli/filebrowser-config-init.md
index 126082d0..6ea484e6 100644
--- a/www/docs/cli/filebrowser-config-init.md
+++ b/www/docs/cli/filebrowser-config-init.md
@@ -17,63 +17,60 @@ filebrowser config init [flags]
## Options
```
- --aceEditorTheme string ace editor's syntax highlighting theme for users
- -a, --address string address to listen on (default "127.0.0.1")
- --auth.command string command for auth.method=hook
- --auth.header string HTTP header for auth.method=proxy
- --auth.method string authentication type (default "json")
- -b, --baseurl string base url
- --branding.color string set the theme color
- --branding.disableExternal disable external links such as GitHub links
- --branding.disableUsedPercentage disable used disk percentage graph
- --branding.files string path to directory with images and custom styles
- --branding.name string replace 'File Browser' by this name
- --branding.theme string set the theme
- --cache-dir string file cache directory (disabled if empty)
- -t, --cert string tls certificate
- --commands strings a list of the commands a user can execute
- --create-user-dir generate user's home directory automatically
- --dateFormat use date format (true for absolute time, false for relative)
- --dir-mode string mode bits that new directories are created with (default "0o750")
- --disable-exec disables Command Runner feature (default true)
- --disable-preview-resize disable resize of image previews
- --disable-thumbnails disable image thumbnails
- --disable-type-detection-by-header disables type detection by reading file headers
- --file-mode string mode bits that new files are created with (default "0o640")
- -h, --help help for init
- --hide-login-button hide login button from public pages
- --hideDotfiles hide dotfiles
- --img-processors int image processors count (default 4)
- -k, --key string tls key
- --locale string locale for users (default "en")
- --lockPassword lock password
- -l, --log string log output (default "stdout")
- --minimum-password-length uint minimum password length for new users (default 12)
- --perm.admin admin perm for users
- --perm.create create perm for users (default true)
- --perm.delete delete perm for users (default true)
- --perm.download download perm for users (default true)
- --perm.execute execute perm for users (default true)
- --perm.modify modify perm for users (default true)
- --perm.rename rename perm for users (default true)
- --perm.share share perm for users (default true)
- -p, --port string port to listen on (default "8080")
- --recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
- --recaptcha.key string ReCaptcha site key
- --recaptcha.secret string ReCaptcha secret
- -r, --root string root to prepend to relative paths (default ".")
- --scope string scope for users (default ".")
- --shell string shell command to which other commands should be appended
- -s, --signup allow users to signup
- --singleClick use single clicks only
- --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
- --socket-perm uint32 unix socket file permissions (default 438)
- --sorting.asc sorting by ascending order
- --sorting.by string sorting mode (name, size or modified) (default "name")
- --token-expiration-time string user session timeout (default "2h")
- --tus.chunkSize uint the tus chunk size (default 10485760)
- --tus.retryCount uint16 the tus retry count (default 5)
- --viewMode string view mode for users (default "list")
+ --aceEditorTheme string ace editor's syntax highlighting theme for users
+ -a, --address string address to listen on (default "127.0.0.1")
+ --auth.command string command for auth.method=hook
+ --auth.header string HTTP header for auth.method=proxy
+ --auth.method string authentication type (default "json")
+ -b, --baseURL string base url
+ --branding.color string set the theme color
+ --branding.disableExternal disable external links such as GitHub links
+ --branding.disableUsedPercentage disable used disk percentage graph
+ --branding.files string path to directory with images and custom styles
+ --branding.name string replace 'File Browser' by this name
+ --branding.theme string set the theme
+ -t, --cert string tls certificate
+ --commands strings a list of the commands a user can execute
+ --createUserDir generate user's home directory automatically
+ --dateFormat use date format (true for absolute time, false for relative)
+ --dirMode string mode bits that new directories are created with (default "0o750")
+ --disableExec disables Command Runner feature (default true)
+ --disablePreviewResize disable resize of image previews
+ --disableThumbnails disable image thumbnails
+ --disableTypeDetectionByHeader disables type detection by reading file headers
+ --fileMode string mode bits that new files are created with (default "0o640")
+ -h, --help help for init
+ --hideDotfiles hide dotfiles
+ --hideLoginButton hide login button from public pages
+ -k, --key string tls key
+ --locale string locale for users (default "en")
+ --lockPassword lock password
+ -l, --log string log output (default "stdout")
+ --minimumPasswordLength uint minimum password length for new users (default 12)
+ --perm.admin admin perm for users
+ --perm.create create perm for users (default true)
+ --perm.delete delete perm for users (default true)
+ --perm.download download perm for users (default true)
+ --perm.execute execute perm for users (default true)
+ --perm.modify modify perm for users (default true)
+ --perm.rename rename perm for users (default true)
+ --perm.share share perm for users (default true)
+ -p, --port string port to listen on (default "8080")
+ --recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
+ --recaptcha.key string ReCaptcha site key
+ --recaptcha.secret string ReCaptcha secret
+ -r, --root string root to prepend to relative paths (default ".")
+ --scope string scope for users (default ".")
+ --shell string shell command to which other commands should be appended
+ -s, --signup allow users to signup
+ --singleClick use single clicks only
+ --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
+ --sorting.asc sorting by ascending order
+ --sorting.by string sorting mode (name, size or modified) (default "name")
+ --tokenExpirationTime string user session timeout (default "2h")
+ --tus.chunkSize uint the tus chunk size (default 10485760)
+ --tus.retryCount uint16 the tus retry count (default 5)
+ --viewMode string view mode for users (default "list")
```
## Options inherited from parent commands
diff --git a/www/docs/cli/filebrowser-config-set.md b/www/docs/cli/filebrowser-config-set.md
index 8d8ea8f5..93515ab4 100644
--- a/www/docs/cli/filebrowser-config-set.md
+++ b/www/docs/cli/filebrowser-config-set.md
@@ -14,63 +14,60 @@ filebrowser config set [flags]
## Options
```
- --aceEditorTheme string ace editor's syntax highlighting theme for users
- -a, --address string address to listen on (default "127.0.0.1")
- --auth.command string command for auth.method=hook
- --auth.header string HTTP header for auth.method=proxy
- --auth.method string authentication type (default "json")
- -b, --baseurl string base url
- --branding.color string set the theme color
- --branding.disableExternal disable external links such as GitHub links
- --branding.disableUsedPercentage disable used disk percentage graph
- --branding.files string path to directory with images and custom styles
- --branding.name string replace 'File Browser' by this name
- --branding.theme string set the theme
- --cache-dir string file cache directory (disabled if empty)
- -t, --cert string tls certificate
- --commands strings a list of the commands a user can execute
- --create-user-dir generate user's home directory automatically
- --dateFormat use date format (true for absolute time, false for relative)
- --dir-mode string mode bits that new directories are created with (default "0o750")
- --disable-exec disables Command Runner feature (default true)
- --disable-preview-resize disable resize of image previews
- --disable-thumbnails disable image thumbnails
- --disable-type-detection-by-header disables type detection by reading file headers
- --file-mode string mode bits that new files are created with (default "0o640")
- -h, --help help for set
- --hide-login-button hide login button from public pages
- --hideDotfiles hide dotfiles
- --img-processors int image processors count (default 4)
- -k, --key string tls key
- --locale string locale for users (default "en")
- --lockPassword lock password
- -l, --log string log output (default "stdout")
- --minimum-password-length uint minimum password length for new users (default 12)
- --perm.admin admin perm for users
- --perm.create create perm for users (default true)
- --perm.delete delete perm for users (default true)
- --perm.download download perm for users (default true)
- --perm.execute execute perm for users (default true)
- --perm.modify modify perm for users (default true)
- --perm.rename rename perm for users (default true)
- --perm.share share perm for users (default true)
- -p, --port string port to listen on (default "8080")
- --recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
- --recaptcha.key string ReCaptcha site key
- --recaptcha.secret string ReCaptcha secret
- -r, --root string root to prepend to relative paths (default ".")
- --scope string scope for users (default ".")
- --shell string shell command to which other commands should be appended
- -s, --signup allow users to signup
- --singleClick use single clicks only
- --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
- --socket-perm uint32 unix socket file permissions (default 438)
- --sorting.asc sorting by ascending order
- --sorting.by string sorting mode (name, size or modified) (default "name")
- --token-expiration-time string user session timeout (default "2h")
- --tus.chunkSize uint the tus chunk size (default 10485760)
- --tus.retryCount uint16 the tus retry count (default 5)
- --viewMode string view mode for users (default "list")
+ --aceEditorTheme string ace editor's syntax highlighting theme for users
+ -a, --address string address to listen on (default "127.0.0.1")
+ --auth.command string command for auth.method=hook
+ --auth.header string HTTP header for auth.method=proxy
+ --auth.method string authentication type (default "json")
+ -b, --baseURL string base url
+ --branding.color string set the theme color
+ --branding.disableExternal disable external links such as GitHub links
+ --branding.disableUsedPercentage disable used disk percentage graph
+ --branding.files string path to directory with images and custom styles
+ --branding.name string replace 'File Browser' by this name
+ --branding.theme string set the theme
+ -t, --cert string tls certificate
+ --commands strings a list of the commands a user can execute
+ --createUserDir generate user's home directory automatically
+ --dateFormat use date format (true for absolute time, false for relative)
+ --dirMode string mode bits that new directories are created with (default "0o750")
+ --disableExec disables Command Runner feature (default true)
+ --disablePreviewResize disable resize of image previews
+ --disableThumbnails disable image thumbnails
+ --disableTypeDetectionByHeader disables type detection by reading file headers
+ --fileMode string mode bits that new files are created with (default "0o640")
+ -h, --help help for set
+ --hideDotfiles hide dotfiles
+ --hideLoginButton hide login button from public pages
+ -k, --key string tls key
+ --locale string locale for users (default "en")
+ --lockPassword lock password
+ -l, --log string log output (default "stdout")
+ --minimumPasswordLength uint minimum password length for new users (default 12)
+ --perm.admin admin perm for users
+ --perm.create create perm for users (default true)
+ --perm.delete delete perm for users (default true)
+ --perm.download download perm for users (default true)
+ --perm.execute execute perm for users (default true)
+ --perm.modify modify perm for users (default true)
+ --perm.rename rename perm for users (default true)
+ --perm.share share perm for users (default true)
+ -p, --port string port to listen on (default "8080")
+ --recaptcha.host string use another host for ReCAPTCHA. recaptcha.net might be useful in China (default "https://www.google.com")
+ --recaptcha.key string ReCaptcha site key
+ --recaptcha.secret string ReCaptcha secret
+ -r, --root string root to prepend to relative paths (default ".")
+ --scope string scope for users (default ".")
+ --shell string shell command to which other commands should be appended
+ -s, --signup allow users to signup
+ --singleClick use single clicks only
+ --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
+ --sorting.asc sorting by ascending order
+ --sorting.by string sorting mode (name, size or modified) (default "name")
+ --tokenExpirationTime string user session timeout (default "2h")
+ --tus.chunkSize uint the tus chunk size (default 10485760)
+ --tus.retryCount uint16 the tus retry count (default 5)
+ --viewMode string view mode for users (default "list")
```
## Options inherited from parent commands
diff --git a/www/docs/cli/filebrowser.md b/www/docs/cli/filebrowser.md
index a8cbe669..8383ec97 100644
--- a/www/docs/cli/filebrowser.md
+++ b/www/docs/cli/filebrowser.md
@@ -13,12 +13,14 @@ it. Don't worry: you don't need to setup a separate database server.
We're using Bolt DB which is a single file database and all managed
by ourselves.
-For this specific command, all the flags you have available (except
-"config" for the configuration file), can be given either through
-environment variables or configuration files.
+For this command, all flags are available as environmental variables,
+except for "--config", which specifies the configuration file to use.
+The environment variables are prefixed by "FB_" followed by the flag name in
+UPPER_SNAKE_CASE. For example, the flag "--disablePreviewResize" is available
+as FB_DISABLE_PREVIEW_RESIZE.
-If you don't set "config", it will look for a configuration file called
-.filebrowser.{json, toml, yaml, yml} in the following directories:
+If "--config" is not specified, File Browser will look for a configuration
+file named .filebrowser.{json, toml, yaml, yml} in the following directories:
- ./
- $HOME/
@@ -26,15 +28,11 @@ If you don't set "config", it will look for a configuration file called
The precedence of the configuration values are as follows:
-- flags
-- environment variables
-- configuration file
-- database values
-- defaults
-
-The environment variables are prefixed by "FB_" followed by the option
-name in caps. So to set "database" via an env variable, you should
-set FB_DATABASE.
+- Flags
+- Environment variables
+- Configuration file
+- Database values
+- Defaults
Also, if the database path doesn't exist, File Browser will enter into
the quick setup mode and a new database will be bootstrapped and a new
@@ -47,28 +45,28 @@ filebrowser [flags]
## Options
```
- -a, --address string address to listen on (default "127.0.0.1")
- -b, --baseurl string base url
- --cache-dir string file cache directory (disabled if empty)
- -t, --cert string tls certificate
- -c, --config string config file path
- -d, --database string database path (default "./filebrowser.db")
- --disable-exec disables Command Runner feature (default true)
- --disable-preview-resize disable resize of image previews
- --disable-thumbnails disable image thumbnails
- --disable-type-detection-by-header disables type detection by reading file headers
- -h, --help help for filebrowser
- --img-processors int image processors count (default 4)
- -k, --key string tls key
- -l, --log string log output (default "stdout")
- --noauth use the noauth auther when using quick setup
- --password string hashed password for the first user when using quick config
- -p, --port string port to listen on (default "8080")
- -r, --root string root to prepend to relative paths (default ".")
- --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
- --socket-perm uint32 unix socket file permissions (default 438)
- --token-expiration-time string user session timeout (default "2h")
- --username string username for the first user when using quick config (default "admin")
+ -a, --address string address to listen on (default "127.0.0.1")
+ -b, --baseURL string base url
+ --cacheDir string file cache directory (disabled if empty)
+ -t, --cert string tls certificate
+ -c, --config string config file path
+ -d, --database string database path (default "./filebrowser.db")
+ --disableExec disables Command Runner feature (default true)
+ --disablePreviewResize disable resize of image previews
+ --disableThumbnails disable image thumbnails
+ --disableTypeDetectionByHeader disables type detection by reading file headers
+ -h, --help help for filebrowser
+ --imageProcessors int image processors count (default 4)
+ -k, --key string tls key
+ -l, --log string log output (default "stdout")
+ --noauth use the noauth auther when using quick setup
+ --password string hashed password for the first user when using quick setup
+ -p, --port string port to listen on (default "8080")
+ -r, --root string root to prepend to relative paths (default ".")
+ --socket string socket to listen to (cannot be used with address, port, cert nor key flags)
+ --socketPerm uint32 unix socket file permissions (default 438)
+ --tokenExpirationTime string user session timeout (default "2h")
+ --username string username for the first user when using quick setup (default "admin")
```
## See Also
From f576d38a7ef975e0affe6f3d285f47f1cd399a16 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 09:39:04 +0100
Subject: [PATCH 030/120] chore(release): 2.48.0
---
CHANGELOG.md | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c25523b..c415321c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,24 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [2.48.0](https://github.com/filebrowser/filebrowser/compare/v2.47.0...v2.48.0) (2025-11-17)
+
+
+### Features
+
+* consistent flags and environment variables ([#5549](https://github.com/filebrowser/filebrowser/issues/5549)) ([0a0cb80](https://github.com/filebrowser/filebrowser/commit/0a0cb8046fce52f1ff926171b34bcdb7cd39aab3))
+
+
+### Bug Fixes
+
+* add tokenExpirationTime to `config init` and troubleshoot docs ([#5546](https://github.com/filebrowser/filebrowser/issues/5546)) ([8c5dc76](https://github.com/filebrowser/filebrowser/commit/8c5dc7641e6f8aadd9e5d5d3b25a2ad9f1ec9a1e))
+* use all available flags in quick setup ([f41585f](https://github.com/filebrowser/filebrowser/commit/f41585f0392d65c08c01ab65b62d3eeb04c03b7d))
+
+
+### Refactorings
+
+* reuse logic for config init and set ([89be0b1](https://github.com/filebrowser/filebrowser/commit/89be0b1873527987dd2dddac746e93b8bc684d46))
+
## [2.47.0](https://github.com/filebrowser/filebrowser/compare/v2.46.1...v2.47.0) (2025-11-16)
From 420adea7e61a1c182cddd6fb2544a0752e5709f7 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 09:58:27 +0100
Subject: [PATCH 031/120] fix: options should only override if set
---
cmd/root.go | 85 +++++++++++++++++++++++++++++------------------------
1 file changed, 46 insertions(+), 39 deletions(-)
diff --git a/cmd/root.go b/cmd/root.go
index 668d06ef..6a44e2f3 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -271,48 +271,64 @@ func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, e
return nil, err
}
- if val, set := vGetStringIsSet(v, "root"); set {
- server.Root = val
- }
-
- if val, set := vGetStringIsSet(v, "baseURL"); set {
- server.BaseURL = val
- }
-
- if val, set := vGetStringIsSet(v, "log"); set {
- server.Log = val
- }
-
isSocketSet := false
isAddrSet := false
- if val, set := vGetStringIsSet(v, "address"); set {
- server.Address = val
- isAddrSet = isAddrSet || set
+ if v.IsSet("address") {
+ server.Address = v.GetString("address")
+ isAddrSet = true
}
- if val, set := vGetStringIsSet(v, "port"); set {
- server.Port = val
- isAddrSet = isAddrSet || set
+ if v.IsSet("log") {
+ server.Log = v.GetString("log")
}
- if val, set := vGetStringIsSet(v, "key"); set {
- server.TLSKey = val
- isAddrSet = isAddrSet || set
+ if v.IsSet("port") {
+ server.Port = v.GetString("port")
+ isAddrSet = true
}
- if val, set := vGetStringIsSet(v, "cert"); set {
- server.TLSCert = val
- isAddrSet = isAddrSet || set
+ if v.IsSet("cert") {
+ server.TLSCert = v.GetString("cert")
+ isAddrSet = true
}
- if val, set := vGetStringIsSet(v, "socket"); set {
- server.Socket = val
- isSocketSet = isSocketSet || set
+ if v.IsSet("key") {
+ server.TLSKey = v.GetString("key")
+ isAddrSet = true
}
- if val, set := vGetStringIsSet(v, "tokenExpirationTime"); set {
- server.TokenExpirationTime = val
+ if v.IsSet("root") {
+ server.Root = v.GetString("root")
+ }
+
+ if v.IsSet("socket") {
+ server.Socket = v.GetString("socket")
+ isSocketSet = true
+ }
+
+ if v.IsSet("baseURL") {
+ server.BaseURL = v.GetString("baseURL")
+ }
+
+ if v.IsSet("tokenExpirationTime") {
+ server.TokenExpirationTime = v.GetString("tokenExpirationTime")
+ }
+
+ if v.IsSet("disableThumbnails") {
+ server.EnableThumbnails = !v.GetBool("disableThumbnails")
+ }
+
+ if v.IsSet("disablePreviewResize") {
+ server.ResizePreview = !v.GetBool("disablePreviewResize")
+ }
+
+ if v.IsSet("disableTypeDetectionByHeader") {
+ server.TypeDetectionByHeader = !v.GetBool("disableTypeDetectionByHeader")
+ }
+
+ if v.IsSet("disableExec") {
+ server.EnableExec = !v.GetBool("disableExec")
}
if isAddrSet && isSocketSet {
@@ -324,11 +340,6 @@ func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, e
server.Socket = ""
}
- server.EnableThumbnails = !v.GetBool("disableThumbnails")
- server.ResizePreview = !v.GetBool("disablePreviewResize")
- server.TypeDetectionByHeader = !v.GetBool("disableTypeDetectionByHeader")
- server.EnableExec = !v.GetBool("disableExec")
-
if server.EnableExec {
log.Println("WARNING: Command Runner feature enabled!")
log.Println("WARNING: This feature has known security vulnerabilities and should not")
@@ -339,10 +350,6 @@ func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, e
return server, nil
}
-func vGetStringIsSet(v *viper.Viper, key string) (string, bool) {
- return v.GetString(key), v.IsSet(key)
-}
-
func setupLog(logMethod string) {
switch logMethod {
case "stdout":
@@ -399,7 +406,7 @@ func quickSetup(d pythonData) error {
}
var err error
- if _, noauth := vGetStringIsSet(d.viper, "noauth"); noauth {
+ if d.viper.GetBool("noauth") {
set.AuthMethod = auth.MethodNoAuth
err = d.store.Auth.Save(&auth.NoAuth{})
} else {
From 00323a8f375ed2b82e38b836ee8b27415b7376a4 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 10:02:29 +0100
Subject: [PATCH 032/120] chore: fix Taskfile commit when change
---
Taskfile.yml | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/Taskfile.yml b/Taskfile.yml
index 5977dff0..378e3409 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -49,7 +49,10 @@ tasks:
cmds:
- task: docs:cli:generate
- git add www/docs/cli
- - "git commit -m 'chore(docs): update CLI documentation'"
+ - |
+ if [[ `git status www/docs/cli --porcelain` ]]; then
+ git commit -m 'chore(docs): update CLI documentation'
+ fi
- task: release:dry-run
- task: release:make
From d759ab0bd8a41ad36e5f58955375c4bc75ad961c Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Mon, 17 Nov 2025 10:02:54 +0100
Subject: [PATCH 033/120] chore(release): 2.48.1
---
CHANGELOG.md | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c415321c..a02ee24a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [2.48.1](https://github.com/filebrowser/filebrowser/compare/v2.48.0...v2.48.1) (2025-11-17)
+
+
+### Bug Fixes
+
+* options should only override if set ([420adea](https://github.com/filebrowser/filebrowser/commit/420adea7e61a1c182cddd6fb2544a0752e5709f7))
+
## [2.48.0](https://github.com/filebrowser/filebrowser/compare/v2.47.0...v2.48.0) (2025-11-17)
From 13e3b46718951d4ba82c968d66d731a6ec8b80eb Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Tue, 18 Nov 2025 08:05:02 +0100
Subject: [PATCH 034/120] chore(deps): update all non-major dependencies
(#5560)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/pnpm-lock.yaml | 121 +++++++++++++++++++++++++++++++---------
1 file changed, 96 insertions(+), 25 deletions(-)
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index db9de505..782f7987 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -101,7 +101,7 @@ importers:
version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
'@tsconfig/node24':
specifier: ^24.0.2
- version: 24.0.2
+ version: 24.0.3
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
@@ -110,7 +110,7 @@ importers:
version: 24.10.1
'@typescript-eslint/eslint-plugin':
specifier: ^8.37.0
- version: 8.46.4(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
+ version: 8.47.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@vitejs/plugin-legacy':
specifier: ^7.2.1
version: 7.2.1(terser@5.44.1)(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))
@@ -1087,8 +1087,8 @@ packages:
cpu: [x64]
os: [win32]
- '@tsconfig/node24@24.0.2':
- resolution: {integrity: sha512-CNeOLUPI9PjbBc1DSIqb3GF/u+3kX/TDe9DKCzoI62mYI4dEDrMQ0r/9+SfYACP4UNMbiTlz7n8H7Rx/xTisQg==}
+ '@tsconfig/node24@24.0.3':
+ resolution: {integrity: sha512-vcERKtKQKHgzt/vfS3Gjasd8SUI2a0WZXpgJURdJsMySpS5+ctgbPfuLj2z/W+w4lAfTWxoN4upKfu2WzIRYnw==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -1123,11 +1123,11 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/eslint-plugin@8.46.4':
- resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==}
+ '@typescript-eslint/eslint-plugin@8.47.0':
+ resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
- '@typescript-eslint/parser': ^8.46.4
+ '@typescript-eslint/parser': ^8.47.0
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <6.0.0'
@@ -1150,6 +1150,12 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
+ '@typescript-eslint/project-service@8.47.0':
+ resolution: {integrity: sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
'@typescript-eslint/scope-manager@8.37.0':
resolution: {integrity: sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1158,6 +1164,10 @@ packages:
resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/scope-manager@8.47.0':
+ resolution: {integrity: sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript-eslint/tsconfig-utils@8.37.0':
resolution: {integrity: sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1170,6 +1180,12 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
+ '@typescript-eslint/tsconfig-utils@8.47.0':
+ resolution: {integrity: sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
'@typescript-eslint/type-utils@8.37.0':
resolution: {integrity: sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1177,8 +1193,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/type-utils@8.46.4':
- resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==}
+ '@typescript-eslint/type-utils@8.47.0':
+ resolution: {integrity: sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1192,6 +1208,10 @@ packages:
resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/types@8.47.0':
+ resolution: {integrity: sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@typescript-eslint/typescript-estree@8.37.0':
resolution: {integrity: sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1204,6 +1224,12 @@ packages:
peerDependencies:
typescript: '>=4.8.4 <6.0.0'
+ '@typescript-eslint/typescript-estree@8.47.0':
+ resolution: {integrity: sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ peerDependencies:
+ typescript: '>=4.8.4 <6.0.0'
+
'@typescript-eslint/utils@8.37.0':
resolution: {integrity: sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -1211,8 +1237,8 @@ packages:
eslint: ^8.57.0 || ^9.0.0
typescript: '>=4.8.4 <5.9.0'
- '@typescript-eslint/utils@8.46.4':
- resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==}
+ '@typescript-eslint/utils@8.47.0':
+ resolution: {integrity: sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
eslint: ^8.57.0 || ^9.0.0
@@ -1226,6 +1252,10 @@ packages:
resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+ '@typescript-eslint/visitor-keys@8.47.0':
+ resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==}
+ engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
'@videojs/http-streaming@3.17.2':
resolution: {integrity: sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g==}
engines: {node: '>=8', npm: '>=5'}
@@ -3498,7 +3528,7 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.52.5':
optional: true
- '@tsconfig/node24@24.0.2': {}
+ '@tsconfig/node24@24.0.3': {}
'@types/estree@1.0.8': {}
@@ -3540,14 +3570,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.37.0(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
- '@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/scope-manager': 8.47.0
+ '@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.47.0(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/visitor-keys': 8.47.0
eslint: 9.39.1
graphemer: 1.4.0
ignore: 7.0.5
@@ -3587,6 +3617,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/project-service@8.47.0(typescript@5.9.3)':
+ dependencies:
+ '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3)
+ '@typescript-eslint/types': 8.47.0
+ debug: 4.4.3
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/scope-manager@8.37.0':
dependencies:
'@typescript-eslint/types': 8.37.0
@@ -3597,6 +3636,11 @@ snapshots:
'@typescript-eslint/types': 8.46.4
'@typescript-eslint/visitor-keys': 8.46.4
+ '@typescript-eslint/scope-manager@8.47.0':
+ dependencies:
+ '@typescript-eslint/types': 8.47.0
+ '@typescript-eslint/visitor-keys': 8.47.0
+
'@typescript-eslint/tsconfig-utils@8.37.0(typescript@5.9.3)':
dependencies:
typescript: 5.9.3
@@ -3605,6 +3649,10 @@ snapshots:
dependencies:
typescript: 5.9.3
+ '@typescript-eslint/tsconfig-utils@8.47.0(typescript@5.9.3)':
+ dependencies:
+ typescript: 5.9.3
+
'@typescript-eslint/type-utils@8.37.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.37.0
@@ -3617,11 +3665,11 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/type-utils@8.47.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
- '@typescript-eslint/utils': 8.46.4(eslint@9.39.1)(typescript@5.9.3)
+ '@typescript-eslint/types': 8.47.0
+ '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
+ '@typescript-eslint/utils': 8.47.0(eslint@9.39.1)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.1
ts-api-utils: 2.1.0(typescript@5.9.3)
@@ -3633,6 +3681,8 @@ snapshots:
'@typescript-eslint/types@8.46.4': {}
+ '@typescript-eslint/types@8.47.0': {}
+
'@typescript-eslint/typescript-estree@8.37.0(typescript@5.9.3)':
dependencies:
'@typescript-eslint/project-service': 8.37.0(typescript@5.9.3)
@@ -3665,6 +3715,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ '@typescript-eslint/typescript-estree@8.47.0(typescript@5.9.3)':
+ dependencies:
+ '@typescript-eslint/project-service': 8.47.0(typescript@5.9.3)
+ '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3)
+ '@typescript-eslint/types': 8.47.0
+ '@typescript-eslint/visitor-keys': 8.47.0
+ debug: 4.4.3
+ fast-glob: 3.3.3
+ is-glob: 4.0.3
+ minimatch: 9.0.5
+ semver: 7.7.3
+ ts-api-utils: 2.1.0(typescript@5.9.3)
+ typescript: 5.9.3
+ transitivePeerDependencies:
+ - supports-color
+
'@typescript-eslint/utils@8.37.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
@@ -3676,12 +3742,12 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@typescript-eslint/utils@8.46.4(eslint@9.39.1)(typescript@5.9.3)':
+ '@typescript-eslint/utils@8.47.0(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
- '@typescript-eslint/scope-manager': 8.46.4
- '@typescript-eslint/types': 8.46.4
- '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
+ '@typescript-eslint/scope-manager': 8.47.0
+ '@typescript-eslint/types': 8.47.0
+ '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3)
eslint: 9.39.1
typescript: 5.9.3
transitivePeerDependencies:
@@ -3697,6 +3763,11 @@ snapshots:
'@typescript-eslint/types': 8.46.4
eslint-visitor-keys: 4.2.1
+ '@typescript-eslint/visitor-keys@8.47.0':
+ dependencies:
+ '@typescript-eslint/types': 8.47.0
+ eslint-visitor-keys: 4.2.1
+
'@videojs/http-streaming@3.17.2(video.js@8.23.4)':
dependencies:
'@babel/runtime': 7.28.4
From fd7b70cf38ac67c8c9ff79f2e7fde5e2ec45a1de Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Tue, 18 Nov 2025 11:29:28 +0100
Subject: [PATCH 035/120] refactor: rename python for clarification
---
cmd/cmds_add.go | 8 +++---
cmd/cmds_ls.go | 6 ++---
cmd/cmds_rm.go | 8 +++---
cmd/config_cat.go | 10 +++----
cmd/config_export.go | 10 +++----
cmd/config_import.go | 14 +++++-----
cmd/config_init.go | 10 +++----
cmd/config_set.go | 16 ++++++------
cmd/root.go | 62 ++++++++++++++++++++++----------------------
cmd/rule_rm.go | 10 +++----
cmd/rules_add.go | 10 +++----
cmd/rules_ls.go | 6 ++---
cmd/users_add.go | 12 ++++-----
cmd/users_export.go | 6 ++---
cmd/users_find.go | 10 +++----
cmd/users_import.go | 14 +++++-----
cmd/users_rm.go | 8 +++---
cmd/users_update.go | 12 ++++-----
cmd/utils.go | 62 +++++++++++++++++++++++---------------------
19 files changed, 148 insertions(+), 146 deletions(-)
diff --git a/cmd/cmds_add.go b/cmd/cmds_add.go
index a4d17061..a209b83f 100644
--- a/cmd/cmds_add.go
+++ b/cmd/cmds_add.go
@@ -15,18 +15,18 @@ var cmdsAddCmd = &cobra.Command{
Short: "Add a command to run on a specific event",
Long: `Add a command to run on a specific event.`,
Args: cobra.MinimumNArgs(2),
- RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
- s, err := d.store.Settings.Get()
+ RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
+ s, err := st.Settings.Get()
if err != nil {
return err
}
command := strings.Join(args[1:], " ")
s.Commands[args[0]] = append(s.Commands[args[0]], command)
- err = d.store.Settings.Save(s)
+ err = st.Settings.Save(s)
if err != nil {
return err
}
printEvents(s.Commands)
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/cmds_ls.go b/cmd/cmds_ls.go
index ad700eb7..694be178 100644
--- a/cmd/cmds_ls.go
+++ b/cmd/cmds_ls.go
@@ -14,8 +14,8 @@ var cmdsLsCmd = &cobra.Command{
Short: "List all commands for each event",
Long: `List all commands for each event.`,
Args: cobra.NoArgs,
- RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
- s, err := d.store.Settings.Get()
+ RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
+ s, err := st.Settings.Get()
if err != nil {
return err
}
@@ -35,5 +35,5 @@ var cmdsLsCmd = &cobra.Command{
}
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/cmds_rm.go b/cmd/cmds_rm.go
index 34089388..861f495f 100644
--- a/cmd/cmds_rm.go
+++ b/cmd/cmds_rm.go
@@ -35,8 +35,8 @@ including 'index_end'.`,
return nil
},
- RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
- s, err := d.store.Settings.Get()
+ RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
+ s, err := st.Settings.Get()
if err != nil {
return err
}
@@ -55,11 +55,11 @@ including 'index_end'.`,
}
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...)
- err = d.store.Settings.Save(s)
+ err = st.Settings.Save(s)
if err != nil {
return err
}
printEvents(s.Commands)
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/config_cat.go b/cmd/config_cat.go
index 39b1f664..b8d2f48f 100644
--- a/cmd/config_cat.go
+++ b/cmd/config_cat.go
@@ -13,19 +13,19 @@ var configCatCmd = &cobra.Command{
Short: "Prints the configuration",
Long: `Prints the configuration.`,
Args: cobra.NoArgs,
- RunE: python(func(_ *cobra.Command, _ []string, d *pythonData) error {
- set, err := d.store.Settings.Get()
+ RunE: withStore(func(_ *cobra.Command, _ []string, st *store) error {
+ set, err := st.Settings.Get()
if err != nil {
return err
}
- ser, err := d.store.Settings.GetServer()
+ ser, err := st.Settings.GetServer()
if err != nil {
return err
}
- auther, err := d.store.Auth.Get(set.AuthMethod)
+ auther, err := st.Auth.Get(set.AuthMethod)
if err != nil {
return err
}
return printSettings(ser, set, auther)
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/config_export.go b/cmd/config_export.go
index 9877fb63..b19c10b6 100644
--- a/cmd/config_export.go
+++ b/cmd/config_export.go
@@ -15,18 +15,18 @@ var configExportCmd = &cobra.Command{
json or yaml file. This exported configuration can be changed,
and imported again with 'config import' command.`,
Args: jsonYamlArg,
- RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
- settings, err := d.store.Settings.Get()
+ RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
+ settings, err := st.Settings.Get()
if err != nil {
return err
}
- server, err := d.store.Settings.GetServer()
+ server, err := st.Settings.GetServer()
if err != nil {
return err
}
- auther, err := d.store.Auth.Get(settings.AuthMethod)
+ auther, err := st.Auth.Get(settings.AuthMethod)
if err != nil {
return err
}
@@ -42,5 +42,5 @@ and imported again with 'config import' command.`,
return err
}
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/config_import.go b/cmd/config_import.go
index 63d394d7..4de34c9b 100644
--- a/cmd/config_import.go
+++ b/cmd/config_import.go
@@ -34,11 +34,11 @@ database.
The path must be for a json or yaml file.`,
Args: jsonYamlArg,
- RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
var key []byte
var err error
- if d.databaseExisted {
- settings, settingErr := d.store.Settings.Get()
+ if st.databaseExisted {
+ settings, settingErr := st.Settings.Get()
if settingErr != nil {
return settingErr
}
@@ -54,12 +54,12 @@ The path must be for a json or yaml file.`,
}
file.Settings.Key = key
- err = d.store.Settings.Save(file.Settings)
+ err = st.Settings.Save(file.Settings)
if err != nil {
return err
}
- err = d.store.Settings.SaveServer(file.Server)
+ err = st.Settings.SaveServer(file.Server)
if err != nil {
return err
}
@@ -98,13 +98,13 @@ The path must be for a json or yaml file.`,
return autherErr
}
- err = d.store.Auth.Save(auther)
+ err = st.Auth.Save(auther)
if err != nil {
return err
}
return printSettings(file.Server, file.Settings, auther)
- }, pythonConfig{allowsNoDatabase: true}),
+ }, storeOptions{allowsNoDatabase: true}),
}
func getAuther(sample auth.Auther, data interface{}) (interface{}, error) {
diff --git a/cmd/config_init.go b/cmd/config_init.go
index 2787f080..359d02a3 100644
--- a/cmd/config_init.go
+++ b/cmd/config_init.go
@@ -22,7 +22,7 @@ this options can be changed in the future with the command
to the defaults when creating new users and you don't
override the options.`,
Args: cobra.NoArgs,
- RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
flags := cmd.Flags()
// Initialize config
@@ -36,17 +36,17 @@ override the options.`,
}
// Save updated config
- err = d.store.Settings.Save(s)
+ err = st.Settings.Save(s)
if err != nil {
return err
}
- err = d.store.Settings.SaveServer(ser)
+ err = st.Settings.SaveServer(ser)
if err != nil {
return err
}
- err = d.store.Auth.Save(auther)
+ err = st.Auth.Save(auther)
if err != nil {
return err
}
@@ -57,5 +57,5 @@ Now add your first user via 'filebrowser users add' and then you just
need to call the main command to boot up the server.
`)
return printSettings(ser, s, auther)
- }, pythonConfig{expectsNoDatabase: true}),
+ }, storeOptions{expectsNoDatabase: true}),
}
diff --git a/cmd/config_set.go b/cmd/config_set.go
index d25b6596..df357a02 100644
--- a/cmd/config_set.go
+++ b/cmd/config_set.go
@@ -15,21 +15,21 @@ var configSetCmd = &cobra.Command{
Long: `Updates the configuration. Set the flags for the options
you want to change. Other options will remain unchanged.`,
Args: cobra.NoArgs,
- RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
flags := cmd.Flags()
// Read existing config
- set, err := d.store.Settings.Get()
+ set, err := st.Settings.Get()
if err != nil {
return err
}
- ser, err := d.store.Settings.GetServer()
+ ser, err := st.Settings.GetServer()
if err != nil {
return err
}
- auther, err := d.store.Auth.Get(set.AuthMethod)
+ auther, err := st.Auth.Get(set.AuthMethod)
if err != nil {
return err
}
@@ -41,21 +41,21 @@ you want to change. Other options will remain unchanged.`,
}
// Save updated config
- err = d.store.Auth.Save(auther)
+ err = st.Auth.Save(auther)
if err != nil {
return err
}
- err = d.store.Settings.Save(set)
+ err = st.Settings.Save(set)
if err != nil {
return err
}
- err = d.store.Settings.SaveServer(ser)
+ err = st.Settings.SaveServer(ser)
if err != nil {
return err
}
return printSettings(ser, set, auther)
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/root.go b/cmd/root.go
index 6a44e2f3..30b70f19 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -146,23 +146,23 @@ The precedence of the configuration values are as follows:
Also, if the database path doesn't exist, File Browser will enter into
the quick setup mode and a new database will be bootstrapped and a new
user created with the credentials from options "username" and "password".`,
- RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
- if !d.databaseExisted {
- err := quickSetup(*d)
+ RunE: withViperAndStore(func(cmd *cobra.Command, _ []string, v *viper.Viper, st *store) error {
+ if !st.databaseExisted {
+ err := quickSetup(v, st.Storage)
if err != nil {
return err
}
}
// build img service
- imgWorkersCount := d.viper.GetInt("imageProcessors")
+ imgWorkersCount := v.GetInt("imageProcessors")
if imgWorkersCount < 1 {
return errors.New("image resize workers count could not be < 1")
}
imageService := img.New(imgWorkersCount)
var fileCache diskcache.Interface = diskcache.NewNoOp()
- cacheDir := d.viper.GetString("cacheDir")
+ cacheDir := v.GetString("cacheDir")
if cacheDir != "" {
if err := os.MkdirAll(cacheDir, 0700); err != nil {
return fmt.Errorf("can't make directory %s: %w", cacheDir, err)
@@ -170,7 +170,7 @@ user created with the credentials from options "username" and "password".`,
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
}
- server, err := getServerSettings(d.viper, d.store)
+ server, err := getServerSettings(v, st.Storage)
if err != nil {
return err
}
@@ -192,7 +192,7 @@ user created with the credentials from options "username" and "password".`,
if err != nil {
return err
}
- socketPerm := d.viper.GetUint32("socketPerm")
+ socketPerm := v.GetUint32("socketPerm")
err = os.Chmod(server.Socket, os.FileMode(socketPerm))
if err != nil {
return err
@@ -221,7 +221,7 @@ user created with the credentials from options "username" and "password".`,
panic(err)
}
- handler, err := fbhttp.NewHandler(imageService, fileCache, d.store, server, assetsFs)
+ handler, err := fbhttp.NewHandler(imageService, fileCache, st.Storage, server, assetsFs)
if err != nil {
return err
}
@@ -262,7 +262,7 @@ user created with the credentials from options "username" and "password".`,
log.Println("Graceful shutdown complete.")
return nil
- }, pythonConfig{allowsNoDatabase: true}),
+ }, storeOptions{allowsNoDatabase: true}),
}
func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, error) {
@@ -368,7 +368,7 @@ func setupLog(logMethod string) {
}
}
-func quickSetup(d pythonData) error {
+func quickSetup(v *viper.Viper, s *storage.Storage) error {
log.Println("Performing quick setup")
set := &settings.Settings{
@@ -382,7 +382,7 @@ func quickSetup(d pythonData) error {
Scope: ".",
Locale: "en",
SingleClick: false,
- AceEditorTheme: d.viper.GetString("defaults.aceEditorTheme"),
+ AceEditorTheme: v.GetString("defaults.aceEditorTheme"),
Perm: users.Permissions{
Admin: false,
Execute: true,
@@ -406,44 +406,44 @@ func quickSetup(d pythonData) error {
}
var err error
- if d.viper.GetBool("noauth") {
+ if v.GetBool("noauth") {
set.AuthMethod = auth.MethodNoAuth
- err = d.store.Auth.Save(&auth.NoAuth{})
+ err = s.Auth.Save(&auth.NoAuth{})
} else {
set.AuthMethod = auth.MethodJSONAuth
- err = d.store.Auth.Save(&auth.JSONAuth{})
+ err = s.Auth.Save(&auth.JSONAuth{})
}
if err != nil {
return err
}
- err = d.store.Settings.Save(set)
+ err = s.Settings.Save(set)
if err != nil {
return err
}
ser := &settings.Server{
- BaseURL: d.viper.GetString("baseURL"),
- Port: d.viper.GetString("port"),
- Log: d.viper.GetString("log"),
- TLSKey: d.viper.GetString("key"),
- TLSCert: d.viper.GetString("cert"),
- Address: d.viper.GetString("address"),
- Root: d.viper.GetString("root"),
- TokenExpirationTime: d.viper.GetString("tokenExpirationTime"),
- EnableThumbnails: !d.viper.GetBool("disableThumbnails"),
- ResizePreview: !d.viper.GetBool("disablePreviewResize"),
- EnableExec: !d.viper.GetBool("disableExec"),
- TypeDetectionByHeader: !d.viper.GetBool("disableTypeDetectionByHeader"),
+ BaseURL: v.GetString("baseURL"),
+ Port: v.GetString("port"),
+ Log: v.GetString("log"),
+ TLSKey: v.GetString("key"),
+ TLSCert: v.GetString("cert"),
+ Address: v.GetString("address"),
+ Root: v.GetString("root"),
+ TokenExpirationTime: v.GetString("tokenExpirationTime"),
+ EnableThumbnails: !v.GetBool("disableThumbnails"),
+ ResizePreview: !v.GetBool("disablePreviewResize"),
+ EnableExec: !v.GetBool("disableExec"),
+ TypeDetectionByHeader: !v.GetBool("disableTypeDetectionByHeader"),
}
- err = d.store.Settings.SaveServer(ser)
+ err = s.Settings.SaveServer(ser)
if err != nil {
return err
}
- username := d.viper.GetString("username")
- password := d.viper.GetString("password")
+ username := v.GetString("username")
+ password := v.GetString("password")
if password == "" {
var pwd string
@@ -474,5 +474,5 @@ func quickSetup(d pythonData) error {
set.Defaults.Apply(user)
user.Perm.Admin = true
- return d.store.Users.Save(user)
+ return s.Users.Save(user)
}
diff --git a/cmd/rule_rm.go b/cmd/rule_rm.go
index 26e801ae..8ed8f151 100644
--- a/cmd/rule_rm.go
+++ b/cmd/rule_rm.go
@@ -40,7 +40,7 @@ including 'index_end'.`,
return nil
},
- RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
i, err := strconv.Atoi(args[0])
if err != nil {
return err
@@ -55,14 +55,14 @@ including 'index_end'.`,
user := func(u *users.User) error {
u.Rules = append(u.Rules[:i], u.Rules[f+1:]...)
- return d.store.Users.Save(u)
+ return st.Users.Save(u)
}
global := func(s *settings.Settings) error {
s.Rules = append(s.Rules[:i], s.Rules[f+1:]...)
- return d.store.Settings.Save(s)
+ return st.Settings.Save(s)
}
- return runRules(d.store, cmd, user, global)
- }, pythonConfig{}),
+ return runRules(st.Storage, cmd, user, global)
+ }, storeOptions{}),
}
diff --git a/cmd/rules_add.go b/cmd/rules_add.go
index d58a6987..3b34d940 100644
--- a/cmd/rules_add.go
+++ b/cmd/rules_add.go
@@ -21,7 +21,7 @@ var rulesAddCmd = &cobra.Command{
Short: "Add a global rule or user rule",
Long: `Add a global rule or user rule.`,
Args: cobra.ExactArgs(1),
- RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
flags := cmd.Flags()
allow, err := flags.GetBool("allow")
@@ -53,14 +53,14 @@ var rulesAddCmd = &cobra.Command{
user := func(u *users.User) error {
u.Rules = append(u.Rules, rule)
- return d.store.Users.Save(u)
+ return st.Users.Save(u)
}
global := func(s *settings.Settings) error {
s.Rules = append(s.Rules, rule)
- return d.store.Settings.Save(s)
+ return st.Settings.Save(s)
}
- return runRules(d.store, cmd, user, global)
- }, pythonConfig{}),
+ return runRules(st.Storage, cmd, user, global)
+ }, storeOptions{}),
}
diff --git a/cmd/rules_ls.go b/cmd/rules_ls.go
index 67a279dc..9aa073d0 100644
--- a/cmd/rules_ls.go
+++ b/cmd/rules_ls.go
@@ -13,7 +13,7 @@ var rulesLsCommand = &cobra.Command{
Short: "List global rules or user specific rules",
Long: `List global rules or user specific rules.`,
Args: cobra.NoArgs,
- RunE: python(func(cmd *cobra.Command, _ []string, d *pythonData) error {
- return runRules(d.store, cmd, nil, nil)
- }, pythonConfig{}),
+ RunE: withStore(func(cmd *cobra.Command, _ []string, st *store) error {
+ return runRules(st.Storage, cmd, nil, nil)
+ }, storeOptions{}),
}
diff --git a/cmd/users_add.go b/cmd/users_add.go
index bfc70069..daf59aa3 100644
--- a/cmd/users_add.go
+++ b/cmd/users_add.go
@@ -16,9 +16,9 @@ var usersAddCmd = &cobra.Command{
Short: "Create a new user",
Long: `Create a new user and add it to the database.`,
Args: cobra.ExactArgs(2),
- RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
flags := cmd.Flags()
- s, err := d.store.Settings.Get()
+ s, err := st.Settings.Get()
if err != nil {
return err
}
@@ -54,14 +54,14 @@ var usersAddCmd = &cobra.Command{
s.Defaults.Apply(user)
- servSettings, err := d.store.Settings.GetServer()
+ servSettings, err := st.Settings.GetServer()
if err != nil {
return err
}
// since getUserDefaults() polluted s.Defaults.Scope
// which makes the Scope not the one saved in the db
// we need the right s.Defaults.Scope here
- s2, err := d.store.Settings.Get()
+ s2, err := st.Settings.Get()
if err != nil {
return err
}
@@ -72,11 +72,11 @@ var usersAddCmd = &cobra.Command{
}
user.Scope = userHome
- err = d.store.Users.Save(user)
+ err = st.Users.Save(user)
if err != nil {
return err
}
printUsers([]*users.User{user})
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/users_export.go b/cmd/users_export.go
index d6009a37..9bbec6d8 100644
--- a/cmd/users_export.go
+++ b/cmd/users_export.go
@@ -14,8 +14,8 @@ var usersExportCmd = &cobra.Command{
Long: `Export all users to a json or yaml file. Please indicate the
path to the file where you want to write the users.`,
Args: jsonYamlArg,
- RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
- list, err := d.store.Users.Gets("")
+ RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
+ list, err := st.Users.Gets("")
if err != nil {
return err
}
@@ -25,5 +25,5 @@ path to the file where you want to write the users.`,
return err
}
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/users_find.go b/cmd/users_find.go
index 0dea071a..09bc8d47 100644
--- a/cmd/users_find.go
+++ b/cmd/users_find.go
@@ -26,7 +26,7 @@ var usersLsCmd = &cobra.Command{
RunE: findUsers,
}
-var findUsers = python(func(_ *cobra.Command, args []string, d *pythonData) error {
+var findUsers = withStore(func(_ *cobra.Command, args []string, st *store) error {
var (
list []*users.User
user *users.User
@@ -36,14 +36,14 @@ var findUsers = python(func(_ *cobra.Command, args []string, d *pythonData) erro
if len(args) == 1 {
username, id := parseUsernameOrID(args[0])
if username != "" {
- user, err = d.store.Users.Get("", username)
+ user, err = st.Users.Get("", username)
} else {
- user, err = d.store.Users.Get("", id)
+ user, err = st.Users.Get("", id)
}
list = []*users.User{user}
} else {
- list, err = d.store.Users.Gets("")
+ list, err = st.Users.Gets("")
}
if err != nil {
@@ -51,4 +51,4 @@ var findUsers = python(func(_ *cobra.Command, args []string, d *pythonData) erro
}
printUsers(list)
return nil
-}, pythonConfig{})
+}, storeOptions{})
diff --git a/cmd/users_import.go b/cmd/users_import.go
index d08889df..73effca6 100644
--- a/cmd/users_import.go
+++ b/cmd/users_import.go
@@ -25,7 +25,7 @@ file. You can use this command to import new users to your
installation. For that, just don't place their ID on the files
list or set it to 0.`,
Args: jsonYamlArg,
- RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
flags := cmd.Flags()
fd, err := os.Open(args[0])
if err != nil {
@@ -52,7 +52,7 @@ list or set it to 0.`,
}
if replace {
- oldUsers, userImportErr := d.store.Users.Gets("")
+ oldUsers, userImportErr := st.Users.Gets("")
if userImportErr != nil {
return userImportErr
}
@@ -63,7 +63,7 @@ list or set it to 0.`,
}
for _, user := range oldUsers {
- err = d.store.Users.Delete(user.ID)
+ err = st.Users.Delete(user.ID)
if err != nil {
return err
}
@@ -76,7 +76,7 @@ list or set it to 0.`,
}
for _, user := range list {
- onDB, err := d.store.Users.Get("", user.ID)
+ onDB, err := st.Users.Get("", user.ID)
// User exists in DB.
if err == nil {
@@ -88,7 +88,7 @@ list or set it to 0.`,
// with the new username. If there is, print an error and cancel the
// operation
if user.Username != onDB.Username {
- if conflictuous, err := d.store.Users.Get("", user.Username); err == nil {
+ if conflictuous, err := st.Users.Get("", user.Username); err == nil {
return usernameConflictError(user.Username, conflictuous.ID, user.ID)
}
}
@@ -98,13 +98,13 @@ list or set it to 0.`,
user.ID = 0
}
- err = d.store.Users.Save(user)
+ err = st.Users.Save(user)
if err != nil {
return err
}
}
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
func usernameConflictError(username string, originalID, newID uint) error {
diff --git a/cmd/users_rm.go b/cmd/users_rm.go
index 55b973f4..492a55c3 100644
--- a/cmd/users_rm.go
+++ b/cmd/users_rm.go
@@ -15,14 +15,14 @@ var usersRmCmd = &cobra.Command{
Short: "Delete a user by username or id",
Long: `Delete a user by username or id`,
Args: cobra.ExactArgs(1),
- RunE: python(func(_ *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(_ *cobra.Command, args []string, st *store) error {
username, id := parseUsernameOrID(args[0])
var err error
if username != "" {
- err = d.store.Users.Delete(username)
+ err = st.Users.Delete(username)
} else {
- err = d.store.Users.Delete(id)
+ err = st.Users.Delete(id)
}
if err != nil {
@@ -30,5 +30,5 @@ var usersRmCmd = &cobra.Command{
}
fmt.Println("user deleted successfully")
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/users_update.go b/cmd/users_update.go
index 59854a81..96f1e2d3 100644
--- a/cmd/users_update.go
+++ b/cmd/users_update.go
@@ -21,7 +21,7 @@ var usersUpdateCmd = &cobra.Command{
Long: `Updates an existing user. Set the flags for the
options you want to change.`,
Args: cobra.ExactArgs(1),
- RunE: python(func(cmd *cobra.Command, args []string, d *pythonData) error {
+ RunE: withStore(func(cmd *cobra.Command, args []string, st *store) error {
flags := cmd.Flags()
username, id := parseUsernameOrID(args[0])
password, err := flags.GetString("password")
@@ -34,7 +34,7 @@ options you want to change.`,
return err
}
- s, err := d.store.Settings.Get()
+ s, err := st.Settings.Get()
if err != nil {
return err
}
@@ -43,9 +43,9 @@ options you want to change.`,
user *users.User
)
if id != 0 {
- user, err = d.store.Users.Get("", id)
+ user, err = st.Users.Get("", id)
} else {
- user, err = d.store.Users.Get("", username)
+ user, err = st.Users.Get("", username)
}
if err != nil {
return err
@@ -99,11 +99,11 @@ options you want to change.`,
}
}
- err = d.store.Users.Update(user)
+ err = st.Users.Update(user)
if err != nil {
return err
}
printUsers([]*users.User{user})
return nil
- }, pythonConfig{}),
+ }, storeOptions{}),
}
diff --git a/cmd/utils.go b/cmd/utils.go
index a136db10..eb953d32 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -36,6 +36,7 @@ func getAndParseFileMode(flags *pflag.FlagSet, name string) (fs.FileMode, error)
if err != nil {
return 0, err
}
+
return fs.FileMode(b), nil
}
@@ -131,38 +132,29 @@ func initViper(cmd *cobra.Command) (*viper.Viper, error) {
return v, nil
}
-type cobraFunc func(cmd *cobra.Command, args []string) error
-type pythonFunc func(cmd *cobra.Command, args []string, data *pythonData) error
+type store struct {
+ *storage.Storage
+ databaseExisted bool
+}
-type pythonConfig struct {
+type storeOptions struct {
expectsNoDatabase bool
allowsNoDatabase bool
}
-type pythonData struct {
- databaseExisted bool
- viper *viper.Viper
- store *storage.Storage
-}
+type cobraFunc func(cmd *cobra.Command, args []string) error
-func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
+// withViperAndStore initializes Viper and the storage.Store and passes them to the callback function.
+// This function should only be used by [withStore] and the root command. No other command should call
+// this function directly.
+func withViperAndStore(fn func(cmd *cobra.Command, args []string, v *viper.Viper, store *store) error, options storeOptions) cobraFunc {
return func(cmd *cobra.Command, args []string) error {
v, err := initViper(cmd)
if err != nil {
return err
}
- data := &pythonData{databaseExisted: true}
- path := v.GetString("database")
-
- // Only make the viper instance available to the root command (filebrowser).
- // This is to make sure that we don't make the mistake of using it somewhere
- // else.
- if cmd.Name() == "filebrowser" {
- data.viper = v
- }
-
- absPath, err := filepath.Abs(path)
+ path, err := filepath.Abs(v.GetString("database"))
if err != nil {
return err
}
@@ -170,16 +162,15 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
exists, err := dbExists(path)
if err != nil {
return err
- } else if exists && cfg.expectsNoDatabase {
- log.Fatal(absPath + " already exists")
- } else if !exists && !cfg.expectsNoDatabase && !cfg.allowsNoDatabase {
- log.Fatal(absPath + " does not exist. Please run 'filebrowser config init' first.")
- } else if !exists && !cfg.expectsNoDatabase {
- log.Println("Warning: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(absPath, "filebrowser.db"))
+ } else if exists && options.expectsNoDatabase {
+ log.Fatal(path + " already exists")
+ } else if !exists && !options.expectsNoDatabase && !options.allowsNoDatabase {
+ log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.")
+ } else if !exists && !options.expectsNoDatabase {
+ log.Println("WARNING: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(path, "filebrowser.db"))
}
- log.Println("Using database: " + absPath)
- data.databaseExisted = exists
+ log.Println("Using database: " + path)
db, err := storm.Open(path, storm.BoltOptions(databasePermissions, nil))
if err != nil {
@@ -187,15 +178,26 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
}
defer db.Close()
- data.store, err = bolt.NewStorage(db)
+ storage, err := bolt.NewStorage(db)
if err != nil {
return err
}
- return fn(cmd, args, data)
+ store := &store{
+ Storage: storage,
+ databaseExisted: exists,
+ }
+
+ return fn(cmd, args, v, store)
}
}
+func withStore(fn func(cmd *cobra.Command, args []string, store *store) error, options storeOptions) cobraFunc {
+ return withViperAndStore(func(cmd *cobra.Command, args []string, v *viper.Viper, store *store) error {
+ return fn(cmd, args, store)
+ }, options)
+}
+
func marshal(filename string, data interface{}) error {
fd, err := os.Create(filename)
if err != nil {
From 984ea7b569e3bd33b6f91ebdf63684a618d51e94 Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Tue, 18 Nov 2025 11:30:43 +0100
Subject: [PATCH 036/120] fix: add transitionary support for FB_BASEURL
---
cmd/root.go | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/cmd/root.go b/cmd/root.go
index 30b70f19..b0ccd8f5 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -59,7 +59,7 @@ func migrateFlagNames(f *pflag.FlagSet, name string) pflag.NormalizedName {
if !warnedFlags[name] {
warnedFlags[name] = true
- fmt.Printf("WARNING: Flag --%s has been deprecated, use --%s instead\n", name, newName)
+ log.Printf("DEPRECATION NOTICE: Flag --%s has been deprecated, use --%s instead\n", name, newName)
}
name = newName
@@ -309,6 +309,10 @@ func getServerSettings(v *viper.Viper, st *storage.Storage) (*settings.Server, e
if v.IsSet("baseURL") {
server.BaseURL = v.GetString("baseURL")
+ // TODO(remove): remove after July 2026.
+ } else if v := os.Getenv("FB_BASEURL"); v != "" {
+ log.Println("DEPRECATION NOTICE: Environment variable FB_BASEURL has been deprecated, use FB_BASE_URL instead")
+ server.BaseURL = v
}
if v.IsSet("tokenExpirationTime") {
From c284de9d2c1f01cb2a7a1c87423108ec531b7bcc Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Tue, 18 Nov 2025 11:32:24 +0100
Subject: [PATCH 037/120] chore(release): 2.48.2
---
CHANGELOG.md | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a02ee24a..5f7ccd26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
+## [2.48.2](https://github.com/filebrowser/filebrowser/compare/v2.48.1...v2.48.2) (2025-11-18)
+
+
+### Bug Fixes
+
+* add transitionary support for FB_BASEURL ([984ea7b](https://github.com/filebrowser/filebrowser/commit/984ea7b569e3bd33b6f91ebdf63684a618d51e94))
+
+
+### Refactorings
+
+* rename python for clarification ([fd7b70c](https://github.com/filebrowser/filebrowser/commit/fd7b70cf38ac67c8c9ff79f2e7fde5e2ec45a1de))
+
## [2.48.1](https://github.com/filebrowser/filebrowser/compare/v2.48.0...v2.48.1) (2025-11-17)
From 8db2411cd43a23ae3292a817e3524cfdb5ae9b86 Mon Sep 17 00:00:00 2001
From: "transifex-integration[bot]"
<43880903+transifex-integration[bot]@users.noreply.github.com>
Date: Wed, 19 Nov 2025 08:14:10 +0100
Subject: [PATCH 038/120] feat: add Bulgarian language
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
Co-authored-by: Henrique Dias
---
.../src/components/settings/Languages.vue | 13 +-
frontend/src/i18n/bg.json | 272 ++++++++++++++++++
frontend/src/i18n/index.ts | 9 +-
3 files changed, 286 insertions(+), 8 deletions(-)
create mode 100644 frontend/src/i18n/bg.json
diff --git a/frontend/src/components/settings/Languages.vue b/frontend/src/components/settings/Languages.vue
index f4e4090e..72968511 100644
--- a/frontend/src/components/settings/Languages.vue
+++ b/frontend/src/components/settings/Languages.vue
@@ -15,10 +15,8 @@ export default {
data() {
const dataObj = {};
const locales = {
- he: "עברית",
- hr: "Hrvatski",
- hu: "Magyar",
ar: "العربية",
+ bg: "български език",
ca: "Català",
cs: "Čeština",
de: "Deutsch",
@@ -26,15 +24,18 @@ export default {
en: "English",
es: "Español",
fr: "Français",
+ he: "עברית",
+ hr: "Hrvatski",
+ hu: "Magyar",
is: "Icelandic",
it: "Italiano",
ja: "日本語",
ko: "한국어",
- "nl-be": "Dutch (Belgium)",
no: "Norsk",
+ "nl-be": "Dutch (Belgium)",
pl: "Polski",
- "pt-br": "Português",
- pt: "Português (Brasil)",
+ "pt-br": "Português (Brasil)",
+ pt: "Português (Portugal)",
ro: "Romanian",
ru: "Русский",
sk: "Slovenčina",
diff --git a/frontend/src/i18n/bg.json b/frontend/src/i18n/bg.json
new file mode 100644
index 00000000..82fa6b1b
--- /dev/null
+++ b/frontend/src/i18n/bg.json
@@ -0,0 +1,272 @@
+{
+ "buttons": {
+ "cancel": "Отмени",
+ "clear": "Изчисти",
+ "close": "Затвори",
+ "continue": "Продължи",
+ "copy": "Копирай",
+ "copyFile": "Копирай файл",
+ "copyToClipboard": "Копирай в клипборда",
+ "copyDownloadLinkToClipboard": "Копирай линк за сваляне в клипборда",
+ "create": "Създай",
+ "delete": "Изтрий",
+ "download": "Свали",
+ "file": "Файл",
+ "folder": "Папка",
+ "fullScreen": "Превключване на цял екран",
+ "hideDotfiles": "Скрий файлове започващи с точка",
+ "info": "Информация",
+ "more": "Повече",
+ "move": "Премести",
+ "moveFile": "Премести файл",
+ "new": "Нов",
+ "next": "Следващ",
+ "ok": "Потвърди",
+ "permalink": "Вземи постоянен линк",
+ "previous": "Предишен",
+ "preview": "Преглед",
+ "publish": "Публикуване",
+ "rename": "Преименуване",
+ "replace": "Замяна",
+ "reportIssue": "Докладвай проблем",
+ "save": "Запис",
+ "schedule": "График",
+ "search": "Търсене",
+ "select": "Избери",
+ "selectMultiple": "Избери няколко",
+ "share": "Сподели",
+ "shell": "Превключване на терминала",
+ "submit": "Изпрати",
+ "switchView": "Смени изгледа",
+ "toggleSidebar": "Превключване на страничен панел",
+ "update": "Обнови",
+ "upload": "Качи",
+ "openFile": "Отвори файл",
+ "discardChanges": "Изчисти",
+ "saveChanges": "Запиши промените"
+ },
+ "download": {
+ "downloadFile": "Свали файл",
+ "downloadFolder": "Свали папка",
+ "downloadSelected": "Свали избраното"
+ },
+ "upload": {
+ "abortUpload": "Сигурни ли сте, че искате да прекратите?"
+ },
+ "errors": {
+ "forbidden": "Нямате право на достъп.",
+ "internal": "Взникна грешка.",
+ "notFound": "Локацията не може да бъде достигната.",
+ "connection": "Сървъра не може да бъде достигнат."
+ },
+ "files": {
+ "body": "Тяло",
+ "closePreview": "Затвори прегледа",
+ "files": "Файлове",
+ "folders": "Папки",
+ "home": "Начало",
+ "lastModified": "Последна промяна",
+ "loading": "Зареждане ...",
+ "lonely": "Тук е самотно ...",
+ "metadata": "Метаданни",
+ "multipleSelectionEnabled": "Множествения избор е разрешен",
+ "name": "Име",
+ "size": "Размер",
+ "sortByLastModified": "Подредба по последна промяна",
+ "sortByName": "Подредба по име",
+ "sortBySize": "Подредба по размер",
+ "noPreview": "За този файл не е наличен преглед."
+ },
+ "help": {
+ "click": "избери файл или директория",
+ "ctrl": {
+ "click": "избери файлове или директории",
+ "f": "отваря търсене",
+ "s": "запиши файл или свари директория тук"
+ },
+ "del": "изтрий избраните",
+ "doubleClick": "отвори файл или директория",
+ "esc": "изтрий избраното и/или затвори",
+ "f1": "тази информация",
+ "f2": "преименувай файл",
+ "help": "Помощ"
+ },
+ "login": {
+ "createAnAccount": "Създай акаунт",
+ "loginInstead": "Вече имаш акаунт",
+ "password": "Парола",
+ "passwordConfirm": "Парола Потвърждение",
+ "passwordsDontMatch": "Паролите не съвпадат",
+ "signup": "Абониране",
+ "submit": "Вход",
+ "username": "Потребителско име",
+ "usernameTaken": "Потребителското име вече се използва",
+ "wrongCredentials": "Грешни потребителско име и/или парола",
+ "logout_reasons": {
+ "inactivity": "Бяхте разлогнати поради неактивност"
+ }
+ },
+ "permanent": "Постоянен",
+ "prompts": {
+ "copy": "Копирай",
+ "copyMessage": "Избери къде да копираш файловете си:",
+ "currentlyNavigating": "В момента навигира към:",
+ "deleteMessageMultiple": "Сигурни ли сте, че искате да изтриете {count} файл(а)?",
+ "deleteMessageSingle": "Сигурни ли сте, че искате да изтриете този файл/папка?",
+ "deleteMessageShare": "Сигурни ли сте, че искате на изтриете това споделяне({path})?",
+ "deleteUser": "Сигурни ли сте, че искате да изтриете този потребител?",
+ "deleteTitle": "Изтрий файлове",
+ "displayName": "Име за показване:",
+ "download": "Свали файлове",
+ "downloadMessage": "Изберете формата, в който искате да свалите.",
+ "error": "Възникна грешка",
+ "fileInfo": "Информация за файла",
+ "filesSelected": "Избрани са {count} файла.",
+ "lastModified": "Последна промяна",
+ "move": "Премести",
+ "moveMessage": "Избери ново място за вашите файл(ове)/папк(а/и):",
+ "newArchetype": "Създай нова публикация базирана на шаблон. Вашия файл ще бъде създаден в папката за съдържание.",
+ "newDir": "Нова директория",
+ "newDirMessage": "Именувайте вашата нова директория.",
+ "newFile": "Нов файл",
+ "newFileMessage": "Именувайте вашия нов файл.",
+ "numberDirs": "Брой на директорийте",
+ "numberFiles": "Брой на файловете",
+ "rename": "Преименувай",
+ "renameMessage": "Вмъкни ново име за",
+ "replace": "Замени",
+ "replaceMessage": "Файл, които се опитвате да качите има конфликтно име. Искате ли да го пропуснете и да продължите качването или да замените съществуващия файл?\n",
+ "schedule": "График",
+ "scheduleMessage": "Изберете дата и час за публикуване на тази публикация.",
+ "show": "Покажи",
+ "size": "Размер",
+ "upload": "Качване",
+ "uploadFiles": "Качване на {files} файла...",
+ "uploadMessage": "Изберете опция за качване.",
+ "optionalPassword": "Опционална парола",
+ "resolution": "Резолюция",
+ "discardEditorChanges": "Сигурни ли сте, че искате да откажете направените промени?"
+ },
+ "search": {
+ "images": "Изображения",
+ "music": "Музика",
+ "pdf": "PDF",
+ "pressToSearch": "За търсене, натиснете Enter ...",
+ "search": "Търсене ...",
+ "typeToSearch": "Пишете за търсене ...",
+ "types": "Типове",
+ "video": "Видео"
+ },
+ "settings": {
+ "aceEditorTheme": "Тема на \"Ace редактор\"",
+ "admin": "Админ",
+ "administrator": "Администратор",
+ "allowCommands": "Изпълни команди",
+ "allowEdit": "Редактира, преименува и изтрива файлове и директории",
+ "allowNew": "Създава нови файлове и директорий",
+ "allowPublish": "Публикува нови публикации и страници",
+ "allowSignup": "Разреши потребителите да се абонират",
+ "hideLoginButton": "Скрий логин бутона от публичните страници",
+ "avoidChanges": "(остави празно за да избегнеш промени)",
+ "branding": "Брандиране",
+ "brandingDirectoryPath": "Брандиране - път до директория",
+ "brandingHelp": "Можете да настроите как изглежда вашия File Browser, като промените името и логото му, да добавите стилове и дори да забраните външни линкове към GitHub.\nЗа повече информация за бандиране се обърнете към {0}",
+ "changePassword": "Промени парола",
+ "commandRunner": "Изпълнение на команди",
+ "commandRunnerHelp": "Тук можете да зададете команди, които да се изпълнят при определени събития. Пишете по една команда на ред. Системните променливите {0} и {1} ще са на разположение, като {0} е релативна на {1}. За повече информация относно тази възможност и наличните системни променливи, моля прочетете {2}.",
+ "commandsUpdated": "Командите са запаметени!",
+ "createUserDir": "Създай автоматично собствена директория на потребителя, когато го добавяш.",
+ "minimumPasswordLength": "Минимална дължина на паролата",
+ "tusUploads": "Качване на части",
+ "tusUploadsHelp": "File Browser поддържа качване на части, което позволява съзадавнето на ефективно, надеждно, и възобновяемо качване на части дори и при ненадеждна мрежа.",
+ "tusUploadsChunkSize": "Максимален размер на заявката (за малки качвания ще бъдат използвано директо качване). Можете да въведете цяло число, което означава размера на данните в байтове, или пък текст от вида на 10MB, 1GB и т.н..",
+ "tusUploadsRetryCount": "Брой повторения, когато част от файл не се качи успешно.",
+ "userHomeBasePath": "Основен път до личните директории на потребителите",
+ "userScopeGenerationPlaceholder": "Обхватът ще бъде автоматично генериран",
+ "createUserHomeDirectory": "Създай лична директория на потребителя",
+ "customStylesheet": "Потребителски Стилове",
+ "defaultUserDescription": "Настройки по подразбиране за нови потребители.",
+ "disableExternalLinks": "Забрани външните връзки (с изключение на документацията)",
+ "disableUsedDiskPercentage": "Забрани графиката за използване на диска",
+ "documentation": "документация",
+ "examples": "Примери",
+ "executeOnShell": "Изпълни в шела",
+ "executeOnShellDescription": "По подразбиране, File Browser изпълнява командите директно. Ако искате да ги изпълните в сесия (като Bash или PowerShell), можете да я дефинирате тук заедно с необходимите аргументи и флагове. Ако това е зададено, командата която изпълните ще бъде добавена като аргумент. Това се отнася както за потребителски команди, така и за обработка на събития.",
+ "globalRules": "Това е общия списък от правила за разрешения или забрани. Те са приложими за всеки потребител. Можете да дефинирате специфични правила в настройките на всеки потребител, които ще имат приоритет над общите.",
+ "globalSettings": "Глобални Настройки",
+ "hideDotfiles": "Скрий фаловете започващи с точка",
+ "insertPath": "Вмъкни пътя",
+ "insertRegex": "Вмъкни регулярен израз",
+ "instanceName": "Име на инстанцията",
+ "language": "Език",
+ "lockPassword": "Забрани на потребителя да променя паролата",
+ "newPassword": "Вашата нова парола",
+ "newPasswordConfirm": "Потвърди вашата нова парола",
+ "newUser": "Нов потребител",
+ "password": "Парола",
+ "passwordUpdated": "Паролата е променена!",
+ "path": "Път",
+ "perm": {
+ "create": "Създаване на файлове и директорий",
+ "delete": "Изтриване на файлове и директорий",
+ "download": "Сваляне",
+ "execute": "Изпълни команди",
+ "modify": "Редактирай файлове",
+ "rename": "Преименувай или премести файлове и директорий",
+ "share": "Сподели файлове"
+ },
+ "permissions": "Разрешения",
+ "permissionsHelp": "Можете да зададете потребител да бъде администратор или да изберете разрешения индивидуално. Ако изберете \"Администратор\" всички други опции ще бъдат автоматично отметнати. Управлението на потребителите е привилегия на администратор.\n",
+ "profileSettings": "Настройки на Профила",
+ "ruleExample1": "предотвратете достъпа до всеки файл започващ с точка (като .git, .gitignore) във всяка папка.\n",
+ "ruleExample2": "блокира достъпа до файл именуван Caddyfile поставен в началото за обхвата.",
+ "rules": "Правила",
+ "rulesHelp": "Тук можете да дефинирате списък от правила за разрешаване и забрана за точно този потребител. Блокираните файлове няма да се покажат в списъците и няма да са достъпни за потребителя. Поддържаме регулярни изрази и пътища релативни на обхвата.\n",
+ "scope": "Обхват",
+ "setDateFormat": "Задайте точен формат на дата",
+ "settingsUpdated": "Настройките са обновени!",
+ "shareDuration": "Продължителност на споделянето",
+ "shareManagement": "Управление на споделянето",
+ "shareDeleted": "Споделянето е премахнато!",
+ "singleClick": "Използвайте единичен клик за да отворите файлове или директорий",
+ "themes": {
+ "default": "Настройки по подразбиране",
+ "dark": "Тъмна",
+ "light": "Светла",
+ "title": "Тема"
+ },
+ "user": "Потребител",
+ "userCommands": "Команди",
+ "userCommandsHelp": "Списък разделен с интервал от наличните команди за този потребител.\n",
+ "userCreated": "Потребителя е създаден!",
+ "userDefaults": "Настройки по подразбиране на потребителя",
+ "userDeleted": "Потребителя е изтрит!",
+ "userManagement": "Управление на потребители",
+ "userUpdated": "Потребителя е обновен!",
+ "username": "Потребителско име",
+ "users": "Потребители"
+ },
+ "sidebar": {
+ "help": "Помощ",
+ "hugoNew": "Hugo New",
+ "login": "Вход",
+ "logout": "Изход",
+ "myFiles": "Моите файлове",
+ "newFile": "Нов файл",
+ "newFolder": "Нова папка",
+ "preview": "Преглед",
+ "settings": "Настройки",
+ "signup": "Абониране",
+ "siteSettings": "Настройки на сървъра"
+ },
+ "success": {
+ "linkCopied": "Връзката е копирана!"
+ },
+ "time": {
+ "days": "Дни",
+ "hours": "Часове",
+ "minutes": "Минути",
+ "seconds": "Секунди",
+ "unit": "Единица за време"
+ }
+}
diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts
index a276ee9d..d576d183 100644
--- a/frontend/src/i18n/index.ts
+++ b/frontend/src/i18n/index.ts
@@ -2,6 +2,8 @@ import dayjs from "dayjs";
import { createI18n } from "vue-i18n";
import("dayjs/locale/ar");
+import("dayjs/locale/bg");
+import("dayjs/locale/cs");
import("dayjs/locale/de");
import("dayjs/locale/el");
import("dayjs/locale/en");
@@ -14,6 +16,7 @@ import("dayjs/locale/is");
import("dayjs/locale/it");
import("dayjs/locale/ja");
import("dayjs/locale/ko");
+import("dayjs/locale/nb");
import("dayjs/locale/nl-be");
import("dayjs/locale/pl");
import("dayjs/locale/pt-br");
@@ -27,8 +30,6 @@ import("dayjs/locale/uk");
import("dayjs/locale/vi");
import("dayjs/locale/zh-cn");
import("dayjs/locale/zh-tw");
-import("dayjs/locale/cs");
-import("dayjs/locale/nb");
// All i18n resources specified in the plugin `include` option can be loaded
// at once using the import syntax
@@ -109,6 +110,7 @@ export function detectLocale() {
case /^uk\b/.test(locale):
locale = "uk";
break;
+
case /^vi\b/.test(locale):
locale = "vi";
break;
@@ -123,6 +125,9 @@ export function detectLocale() {
case /^no\b/.test(locale):
locale = "no";
break;
+ case /^bg\b/.test(locale):
+ locale = "bg";
+ break;
default:
locale = "en";
}
From a3b5584505a5430aa9facfaa2025826259533010 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Wed, 19 Nov 2025 08:14:22 +0100
Subject: [PATCH 039/120] chore(deps): update dependency @vitejs/plugin-vue to
v6.0.2 (#5564)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/pnpm-lock.yaml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 782f7987..9feb6b3b 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -116,7 +116,7 @@ importers:
version: 7.2.1(terser@5.44.1)(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))
'@vitejs/plugin-vue':
specifier: ^6.0.1
- version: 6.0.1(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))
+ version: 6.0.2(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))
'@vue/eslint-config-prettier':
specifier: ^10.2.0
version: 10.2.0(eslint@9.39.1)(prettier@3.6.2)
@@ -965,8 +965,8 @@ packages:
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
- '@rolldown/pluginutils@1.0.0-beta.29':
- resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==}
+ '@rolldown/pluginutils@1.0.0-beta.50':
+ resolution: {integrity: sha512-5e76wQiQVeL1ICOZVUg4LSOVYg9jyhGCin+icYozhsUzM+fHE7kddi1bdiE0jwVqTfkjba3jUFbEkoC9WkdvyA==}
'@rollup/pluginutils@5.3.0':
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
@@ -1276,8 +1276,8 @@ packages:
terser: ^5.16.0
vite: ^7.0.0
- '@vitejs/plugin-vue@6.0.1':
- resolution: {integrity: sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==}
+ '@vitejs/plugin-vue@6.0.2':
+ resolution: {integrity: sha512-iHmwV3QcVGGvSC1BG5bZ4z6iwa1SOpAPWmnjOErd4Ske+lZua5K9TtAVdx0gMBClJ28DViCbSmZitjWZsWO3LA==}
engines: {node: ^20.19.0 || >=22.12.0}
peerDependencies:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
@@ -3452,7 +3452,7 @@ snapshots:
'@pkgr/core@0.2.9': {}
- '@rolldown/pluginutils@1.0.0-beta.29': {}
+ '@rolldown/pluginutils@1.0.0-beta.50': {}
'@rollup/pluginutils@5.3.0(rollup@4.52.5)':
dependencies:
@@ -3809,9 +3809,9 @@ snapshots:
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-vue@6.0.1(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))':
+ '@vitejs/plugin-vue@6.0.2(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))':
dependencies:
- '@rolldown/pluginutils': 1.0.0-beta.29
+ '@rolldown/pluginutils': 1.0.0-beta.50
vite: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
vue: 3.5.24(typescript@5.9.3)
From 6d5aa355e433d613e5a3ae137f410c63baeddf0f Mon Sep 17 00:00:00 2001
From: Brian Fromm <69060375+brianfromm@users.noreply.github.com>
Date: Wed, 19 Nov 2025 09:42:50 -0700
Subject: [PATCH 040/120] fix: display friendly error message for password
validation on signup (#5563)
Co-authored-by: Claude
---
frontend/src/i18n/en.json | 1 +
frontend/src/utils/auth.ts | 6 +++++-
frontend/src/views/Login.vue | 7 +++++++
3 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 9272cff4..d7299444 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -102,6 +102,7 @@
"username": "Username",
"usernameTaken": "Username already taken",
"wrongCredentials": "Wrong credentials",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/utils/auth.ts b/frontend/src/utils/auth.ts
index 57e665ea..dcd1cdc5 100644
--- a/frontend/src/utils/auth.ts
+++ b/frontend/src/utils/auth.ts
@@ -101,7 +101,11 @@ export async function signup(username: string, password: string) {
});
if (res.status !== 200) {
- throw new StatusError(`${res.status} ${res.statusText}`, res.status);
+ const body = await res.text();
+ throw new StatusError(
+ body || `${res.status} ${res.statusText}`,
+ res.status
+ );
}
}
diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue
index c0e78225..c7f64a5b 100644
--- a/frontend/src/views/Login.vue
+++ b/frontend/src/views/Login.vue
@@ -112,6 +112,13 @@ const submit = async (event: Event) => {
error.value = t("login.usernameTaken");
} else if (e.status === 403) {
error.value = t("login.wrongCredentials");
+ } else if (e.status === 400) {
+ const match = e.message.match(/minimum length is (\d+)/);
+ if (match) {
+ error.value = t("login.passwordTooShort", { min: match[1] });
+ } else {
+ error.value = e.message;
+ }
} else {
$showError(e);
}
From 5df5508a856ba4e46702aff77ad334c8c99c9ffe Mon Sep 17 00:00:00 2001
From: Henrique Dias
Date: Thu, 20 Nov 2025 07:56:56 +0100
Subject: [PATCH 041/120] chore: add govet, gocritic and revive
---
.golangci.yml | 5 +++++
cmd/docs.go | 2 +-
cmd/root.go | 4 ++--
cmd/utils.go | 11 ++++++-----
diskcache/file_cache_test.go | 6 +++---
5 files changed, 17 insertions(+), 11 deletions(-)
diff --git a/.golangci.yml b/.golangci.yml
index 32d944f3..8819f48b 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -2,8 +2,13 @@ version: "2"
linters:
default: standard
+ enable:
+ - gocritic
+ - govet
+ - revive
exclusions:
presets:
- std-error-handling
+ - comments
paths:
- frontend/
diff --git a/cmd/docs.go b/cmd/docs.go
index 7f4f536e..d65a29be 100644
--- a/cmd/docs.go
+++ b/cmd/docs.go
@@ -35,7 +35,7 @@ var docsCmd = &cobra.Command{
rootCmd.Root().DisableAutoGenTag = true
- err = doc.GenMarkdownTreeCustom(cmd.Root(), tempDir, func(f string) string {
+ err = doc.GenMarkdownTreeCustom(cmd.Root(), tempDir, func(_ string) string {
return ""
}, func(s string) string {
return s
diff --git a/cmd/root.go b/cmd/root.go
index b0ccd8f5..dd91c1b2 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -54,7 +54,7 @@ var (
)
// TODO(remove): remove after July 2026.
-func migrateFlagNames(f *pflag.FlagSet, name string) pflag.NormalizedName {
+func migrateFlagNames(_ *pflag.FlagSet, name string) pflag.NormalizedName {
if newName, ok := flagNamesMigrations[name]; ok {
if !warnedFlags[name] {
@@ -146,7 +146,7 @@ The precedence of the configuration values are as follows:
Also, if the database path doesn't exist, File Browser will enter into
the quick setup mode and a new database will be bootstrapped and a new
user created with the credentials from options "username" and "password".`,
- RunE: withViperAndStore(func(cmd *cobra.Command, _ []string, v *viper.Viper, st *store) error {
+ RunE: withViperAndStore(func(_ *cobra.Command, _ []string, v *viper.Viper, st *store) error {
if !st.databaseExisted {
err := quickSetup(v, st.Storage)
if err != nil {
diff --git a/cmd/utils.go b/cmd/utils.go
index eb953d32..ee637fa3 100644
--- a/cmd/utils.go
+++ b/cmd/utils.go
@@ -160,13 +160,14 @@ func withViperAndStore(fn func(cmd *cobra.Command, args []string, v *viper.Viper
}
exists, err := dbExists(path)
- if err != nil {
+ switch {
+ case err != nil:
return err
- } else if exists && options.expectsNoDatabase {
+ case exists && options.expectsNoDatabase:
log.Fatal(path + " already exists")
- } else if !exists && !options.expectsNoDatabase && !options.allowsNoDatabase {
+ case !exists && !options.expectsNoDatabase && !options.allowsNoDatabase:
log.Fatal(path + " does not exist. Please run 'filebrowser config init' first.")
- } else if !exists && !options.expectsNoDatabase {
+ case !exists && !options.expectsNoDatabase:
log.Println("WARNING: filebrowser.db can't be found. Initialing in " + strings.TrimSuffix(path, "filebrowser.db"))
}
@@ -193,7 +194,7 @@ func withViperAndStore(fn func(cmd *cobra.Command, args []string, v *viper.Viper
}
func withStore(fn func(cmd *cobra.Command, args []string, store *store) error, options storeOptions) cobraFunc {
- return withViperAndStore(func(cmd *cobra.Command, args []string, v *viper.Viper, store *store) error {
+ return withViperAndStore(func(cmd *cobra.Command, args []string, _ *viper.Viper, store *store) error {
return fn(cmd, args, store)
}, options)
}
diff --git a/diskcache/file_cache_test.go b/diskcache/file_cache_test.go
index 9a41052e..c6c750c0 100644
--- a/diskcache/file_cache_test.go
+++ b/diskcache/file_cache_test.go
@@ -25,12 +25,12 @@ func TestFileCache(t *testing.T) {
// store new key
err := cache.Store(ctx, key, []byte(value))
require.NoError(t, err)
- checkValue(t, ctx, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, value)
+ checkValue(ctx, t, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, value)
// update existing key
err = cache.Store(ctx, key, []byte(newValue))
require.NoError(t, err)
- checkValue(t, ctx, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, newValue)
+ checkValue(ctx, t, fs, filepath.Join(cacheRoot, cachedFilePath), cache, key, newValue)
// delete key
err = cache.Delete(ctx, key)
@@ -40,7 +40,7 @@ func TestFileCache(t *testing.T) {
require.False(t, exists)
}
-func checkValue(t *testing.T, ctx context.Context, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) {
+func checkValue(ctx context.Context, t *testing.T, fs afero.Fs, fileFullPath string, cache *FileCache, key, wantValue string) {
t.Helper()
// check actual file content
b, err := afero.ReadFile(fs, fileFullPath)
From ab367a27407a06fe934278698f7ae296e4e1584a Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 20 Nov 2025 09:58:37 +0100
Subject: [PATCH 042/120] chore(deps): update all non-major dependencies
(#5567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/pnpm-lock.yaml | 438 ++++++++++++++++++++--------------------
go.mod | 4 +-
go.sum | 8 +-
3 files changed, 225 insertions(+), 225 deletions(-)
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 9feb6b3b..39576330 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -98,7 +98,7 @@ importers:
devDependencies:
'@intlify/unplugin-vue-i18n':
specifier: ^11.0.1
- version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
+ version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
'@tsconfig/node24':
specifier: ^24.0.2
version: 24.0.3
@@ -113,10 +113,10 @@ importers:
version: 8.47.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(typescript@5.9.3)
'@vitejs/plugin-legacy':
specifier: ^7.2.1
- version: 7.2.1(terser@5.44.1)(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))
+ version: 7.2.1(terser@5.44.1)(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))
'@vitejs/plugin-vue':
specifier: ^6.0.1
- version: 6.0.2(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))
+ version: 6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))
'@vue/eslint-config-prettier':
specifier: ^10.2.0
version: 10.2.0(eslint@9.39.1)(prettier@3.6.2)
@@ -155,10 +155,10 @@ importers:
version: 5.9.3
vite:
specifier: ^7.2.2
- version: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
+ version: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
vite-plugin-compression2:
specifier: ^2.3.1
- version: 2.3.1(rollup@4.52.5)
+ version: 2.3.1(rollup@4.53.3)
vue-tsc:
specifier: ^3.1.3
version: 3.1.4(typescript@5.9.3)
@@ -665,158 +665,158 @@ packages:
peerDependencies:
vue: ^3.0.0
- '@esbuild/aix-ppc64@0.25.11':
- resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==}
+ '@esbuild/aix-ppc64@0.25.12':
+ resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
- '@esbuild/android-arm64@0.25.11':
- resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==}
+ '@esbuild/android-arm64@0.25.12':
+ resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
- '@esbuild/android-arm@0.25.11':
- resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==}
+ '@esbuild/android-arm@0.25.12':
+ resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
- '@esbuild/android-x64@0.25.11':
- resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==}
+ '@esbuild/android-x64@0.25.12':
+ resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
- '@esbuild/darwin-arm64@0.25.11':
- resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==}
+ '@esbuild/darwin-arm64@0.25.12':
+ resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
- '@esbuild/darwin-x64@0.25.11':
- resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==}
+ '@esbuild/darwin-x64@0.25.12':
+ resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
- '@esbuild/freebsd-arm64@0.25.11':
- resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==}
+ '@esbuild/freebsd-arm64@0.25.12':
+ resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
- '@esbuild/freebsd-x64@0.25.11':
- resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==}
+ '@esbuild/freebsd-x64@0.25.12':
+ resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
- '@esbuild/linux-arm64@0.25.11':
- resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==}
+ '@esbuild/linux-arm64@0.25.12':
+ resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
- '@esbuild/linux-arm@0.25.11':
- resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==}
+ '@esbuild/linux-arm@0.25.12':
+ resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
- '@esbuild/linux-ia32@0.25.11':
- resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==}
+ '@esbuild/linux-ia32@0.25.12':
+ resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
- '@esbuild/linux-loong64@0.25.11':
- resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==}
+ '@esbuild/linux-loong64@0.25.12':
+ resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
- '@esbuild/linux-mips64el@0.25.11':
- resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==}
+ '@esbuild/linux-mips64el@0.25.12':
+ resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
- '@esbuild/linux-ppc64@0.25.11':
- resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==}
+ '@esbuild/linux-ppc64@0.25.12':
+ resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
- '@esbuild/linux-riscv64@0.25.11':
- resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==}
+ '@esbuild/linux-riscv64@0.25.12':
+ resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
- '@esbuild/linux-s390x@0.25.11':
- resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==}
+ '@esbuild/linux-s390x@0.25.12':
+ resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
- '@esbuild/linux-x64@0.25.11':
- resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==}
+ '@esbuild/linux-x64@0.25.12':
+ resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
- '@esbuild/netbsd-arm64@0.25.11':
- resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==}
+ '@esbuild/netbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
- '@esbuild/netbsd-x64@0.25.11':
- resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==}
+ '@esbuild/netbsd-x64@0.25.12':
+ resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
- '@esbuild/openbsd-arm64@0.25.11':
- resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==}
+ '@esbuild/openbsd-arm64@0.25.12':
+ resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
- '@esbuild/openbsd-x64@0.25.11':
- resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==}
+ '@esbuild/openbsd-x64@0.25.12':
+ resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
- '@esbuild/openharmony-arm64@0.25.11':
- resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==}
+ '@esbuild/openharmony-arm64@0.25.12':
+ resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
- '@esbuild/sunos-x64@0.25.11':
- resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==}
+ '@esbuild/sunos-x64@0.25.12':
+ resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
- '@esbuild/win32-arm64@0.25.11':
- resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==}
+ '@esbuild/win32-arm64@0.25.12':
+ resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
- '@esbuild/win32-ia32@0.25.11':
- resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==}
+ '@esbuild/win32-ia32@0.25.12':
+ resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
- '@esbuild/win32-x64@0.25.11':
- resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==}
+ '@esbuild/win32-x64@0.25.12':
+ resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
@@ -977,113 +977,113 @@ packages:
rollup:
optional: true
- '@rollup/rollup-android-arm-eabi@4.52.5':
- resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==}
+ '@rollup/rollup-android-arm-eabi@4.53.3':
+ resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==}
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.52.5':
- resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==}
+ '@rollup/rollup-android-arm64@4.53.3':
+ resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==}
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.52.5':
- resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==}
+ '@rollup/rollup-darwin-arm64@4.53.3':
+ resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.52.5':
- resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==}
+ '@rollup/rollup-darwin-x64@4.53.3':
+ resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-freebsd-arm64@4.52.5':
- resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==}
+ '@rollup/rollup-freebsd-arm64@4.53.3':
+ resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==}
cpu: [arm64]
os: [freebsd]
- '@rollup/rollup-freebsd-x64@4.52.5':
- resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==}
+ '@rollup/rollup-freebsd-x64@4.53.3':
+ resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==}
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-linux-arm-gnueabihf@4.52.5':
- resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.53.3':
+ resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.52.5':
- resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==}
+ '@rollup/rollup-linux-arm-musleabihf@4.53.3':
+ resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.52.5':
- resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==}
+ '@rollup/rollup-linux-arm64-gnu@4.53.3':
+ resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.52.5':
- resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==}
+ '@rollup/rollup-linux-arm64-musl@4.53.3':
+ resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-loong64-gnu@4.52.5':
- resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==}
+ '@rollup/rollup-linux-loong64-gnu@4.53.3':
+ resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==}
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-ppc64-gnu@4.52.5':
- resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==}
+ '@rollup/rollup-linux-ppc64-gnu@4.53.3':
+ resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.52.5':
- resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==}
+ '@rollup/rollup-linux-riscv64-gnu@4.53.3':
+ resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-riscv64-musl@4.52.5':
- resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==}
+ '@rollup/rollup-linux-riscv64-musl@4.53.3':
+ resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.52.5':
- resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==}
+ '@rollup/rollup-linux-s390x-gnu@4.53.3':
+ resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==}
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.52.5':
- resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==}
+ '@rollup/rollup-linux-x64-gnu@4.53.3':
+ resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.52.5':
- resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==}
+ '@rollup/rollup-linux-x64-musl@4.53.3':
+ resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-openharmony-arm64@4.52.5':
- resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==}
+ '@rollup/rollup-openharmony-arm64@4.53.3':
+ resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==}
cpu: [arm64]
os: [openharmony]
- '@rollup/rollup-win32-arm64-msvc@4.52.5':
- resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==}
+ '@rollup/rollup-win32-arm64-msvc@4.53.3':
+ resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.52.5':
- resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==}
+ '@rollup/rollup-win32-ia32-msvc@4.53.3':
+ resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-gnu@4.52.5':
- resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==}
+ '@rollup/rollup-win32-x64-gnu@4.53.3':
+ resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==}
cpu: [x64]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.52.5':
- resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==}
+ '@rollup/rollup-win32-x64-msvc@4.53.3':
+ resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==}
cpu: [x64]
os: [win32]
@@ -1626,8 +1626,8 @@ packages:
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
engines: {node: '>=0.12'}
- esbuild@0.25.11:
- resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==}
+ esbuild@0.25.12:
+ resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
engines: {node: '>=18'}
hasBin: true
@@ -2244,8 +2244,8 @@ packages:
rfdc@1.4.1:
resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==}
- rollup@4.52.5:
- resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==}
+ rollup@4.53.3:
+ resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -2435,8 +2435,8 @@ packages:
vite-plugin-compression2@2.3.1:
resolution: {integrity: sha512-bnhLTsurtvOiiP6EMISIKVsOMCeTAjE6FJbyqQus3W4mtAxF7pCuC4puUIAiCgNs98tOCpqo6GIXJXTLufzIaw==}
- vite@7.2.2:
- resolution: {integrity: sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==}
+ vite@7.2.4:
+ resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==}
engines: {node: ^20.19.0 || >=22.12.0}
hasBin: true
peerDependencies:
@@ -3220,82 +3220,82 @@ snapshots:
dependencies:
vue: 3.5.24(typescript@5.9.3)
- '@esbuild/aix-ppc64@0.25.11':
+ '@esbuild/aix-ppc64@0.25.12':
optional: true
- '@esbuild/android-arm64@0.25.11':
+ '@esbuild/android-arm64@0.25.12':
optional: true
- '@esbuild/android-arm@0.25.11':
+ '@esbuild/android-arm@0.25.12':
optional: true
- '@esbuild/android-x64@0.25.11':
+ '@esbuild/android-x64@0.25.12':
optional: true
- '@esbuild/darwin-arm64@0.25.11':
+ '@esbuild/darwin-arm64@0.25.12':
optional: true
- '@esbuild/darwin-x64@0.25.11':
+ '@esbuild/darwin-x64@0.25.12':
optional: true
- '@esbuild/freebsd-arm64@0.25.11':
+ '@esbuild/freebsd-arm64@0.25.12':
optional: true
- '@esbuild/freebsd-x64@0.25.11':
+ '@esbuild/freebsd-x64@0.25.12':
optional: true
- '@esbuild/linux-arm64@0.25.11':
+ '@esbuild/linux-arm64@0.25.12':
optional: true
- '@esbuild/linux-arm@0.25.11':
+ '@esbuild/linux-arm@0.25.12':
optional: true
- '@esbuild/linux-ia32@0.25.11':
+ '@esbuild/linux-ia32@0.25.12':
optional: true
- '@esbuild/linux-loong64@0.25.11':
+ '@esbuild/linux-loong64@0.25.12':
optional: true
- '@esbuild/linux-mips64el@0.25.11':
+ '@esbuild/linux-mips64el@0.25.12':
optional: true
- '@esbuild/linux-ppc64@0.25.11':
+ '@esbuild/linux-ppc64@0.25.12':
optional: true
- '@esbuild/linux-riscv64@0.25.11':
+ '@esbuild/linux-riscv64@0.25.12':
optional: true
- '@esbuild/linux-s390x@0.25.11':
+ '@esbuild/linux-s390x@0.25.12':
optional: true
- '@esbuild/linux-x64@0.25.11':
+ '@esbuild/linux-x64@0.25.12':
optional: true
- '@esbuild/netbsd-arm64@0.25.11':
+ '@esbuild/netbsd-arm64@0.25.12':
optional: true
- '@esbuild/netbsd-x64@0.25.11':
+ '@esbuild/netbsd-x64@0.25.12':
optional: true
- '@esbuild/openbsd-arm64@0.25.11':
+ '@esbuild/openbsd-arm64@0.25.12':
optional: true
- '@esbuild/openbsd-x64@0.25.11':
+ '@esbuild/openbsd-x64@0.25.12':
optional: true
- '@esbuild/openharmony-arm64@0.25.11':
+ '@esbuild/openharmony-arm64@0.25.12':
optional: true
- '@esbuild/sunos-x64@0.25.11':
+ '@esbuild/sunos-x64@0.25.12':
optional: true
- '@esbuild/win32-arm64@0.25.11':
+ '@esbuild/win32-arm64@0.25.12':
optional: true
- '@esbuild/win32-ia32@0.25.11':
+ '@esbuild/win32-ia32@0.25.12':
optional: true
- '@esbuild/win32-x64@0.25.11':
+ '@esbuild/win32-x64@0.25.12':
optional: true
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)':
@@ -3360,7 +3360,7 @@ snapshots:
'@intlify/message-compiler': 11.1.12
'@intlify/shared': 11.1.12
acorn: 8.15.0
- esbuild: 0.25.11
+ esbuild: 0.25.12
escodegen: 2.1.0
estree-walker: 2.0.2
jsonc-eslint-parser: 2.4.0
@@ -3381,13 +3381,13 @@ snapshots:
'@intlify/shared@11.1.12': {}
- '@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
+ '@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
'@intlify/bundle-utils': 11.0.1(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))
'@intlify/shared': 11.1.12
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
- '@rollup/pluginutils': 5.3.0(rollup@4.52.5)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@typescript-eslint/scope-manager': 8.46.4
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
debug: 4.4.3
@@ -3454,78 +3454,78 @@ snapshots:
'@rolldown/pluginutils@1.0.0-beta.50': {}
- '@rollup/pluginutils@5.3.0(rollup@4.52.5)':
+ '@rollup/pluginutils@5.3.0(rollup@4.53.3)':
dependencies:
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.3
optionalDependencies:
- rollup: 4.52.5
+ rollup: 4.53.3
- '@rollup/rollup-android-arm-eabi@4.52.5':
+ '@rollup/rollup-android-arm-eabi@4.53.3':
optional: true
- '@rollup/rollup-android-arm64@4.52.5':
+ '@rollup/rollup-android-arm64@4.53.3':
optional: true
- '@rollup/rollup-darwin-arm64@4.52.5':
+ '@rollup/rollup-darwin-arm64@4.53.3':
optional: true
- '@rollup/rollup-darwin-x64@4.52.5':
+ '@rollup/rollup-darwin-x64@4.53.3':
optional: true
- '@rollup/rollup-freebsd-arm64@4.52.5':
+ '@rollup/rollup-freebsd-arm64@4.53.3':
optional: true
- '@rollup/rollup-freebsd-x64@4.52.5':
+ '@rollup/rollup-freebsd-x64@4.53.3':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.52.5':
+ '@rollup/rollup-linux-arm-gnueabihf@4.53.3':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.52.5':
+ '@rollup/rollup-linux-arm-musleabihf@4.53.3':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.52.5':
+ '@rollup/rollup-linux-arm64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.52.5':
+ '@rollup/rollup-linux-arm64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-loong64-gnu@4.52.5':
+ '@rollup/rollup-linux-loong64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-ppc64-gnu@4.52.5':
+ '@rollup/rollup-linux-ppc64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.52.5':
+ '@rollup/rollup-linux-riscv64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-riscv64-musl@4.52.5':
+ '@rollup/rollup-linux-riscv64-musl@4.53.3':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.52.5':
+ '@rollup/rollup-linux-s390x-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.52.5':
+ '@rollup/rollup-linux-x64-gnu@4.53.3':
optional: true
- '@rollup/rollup-linux-x64-musl@4.52.5':
+ '@rollup/rollup-linux-x64-musl@4.53.3':
optional: true
- '@rollup/rollup-openharmony-arm64@4.52.5':
+ '@rollup/rollup-openharmony-arm64@4.53.3':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.52.5':
+ '@rollup/rollup-win32-arm64-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.52.5':
+ '@rollup/rollup-win32-ia32-msvc@4.53.3':
optional: true
- '@rollup/rollup-win32-x64-gnu@4.52.5':
+ '@rollup/rollup-win32-x64-gnu@4.53.3':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.52.5':
+ '@rollup/rollup-win32-x64-msvc@4.53.3':
optional: true
'@tsconfig/node24@24.0.3': {}
@@ -3790,7 +3790,7 @@ snapshots:
global: 4.4.0
is-function: 1.0.2
- '@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))':
+ '@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))':
dependencies:
'@babel/core': 7.28.5
'@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5)
@@ -3805,14 +3805,14 @@ snapshots:
regenerator-runtime: 0.14.1
systemjs: 6.15.1
terser: 5.44.1
- vite: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
+ vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-vue@6.0.2(vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))':
+ '@vitejs/plugin-vue@6.0.2(vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0))(vue@3.5.24(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.50
- vite: 7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
+ vite: 7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0)
vue: 3.5.24(typescript@5.9.3)
'@volar/language-core@2.4.23':
@@ -4169,34 +4169,34 @@ snapshots:
d: 1.0.2
ext: 1.7.0
- esbuild@0.25.11:
+ esbuild@0.25.12:
optionalDependencies:
- '@esbuild/aix-ppc64': 0.25.11
- '@esbuild/android-arm': 0.25.11
- '@esbuild/android-arm64': 0.25.11
- '@esbuild/android-x64': 0.25.11
- '@esbuild/darwin-arm64': 0.25.11
- '@esbuild/darwin-x64': 0.25.11
- '@esbuild/freebsd-arm64': 0.25.11
- '@esbuild/freebsd-x64': 0.25.11
- '@esbuild/linux-arm': 0.25.11
- '@esbuild/linux-arm64': 0.25.11
- '@esbuild/linux-ia32': 0.25.11
- '@esbuild/linux-loong64': 0.25.11
- '@esbuild/linux-mips64el': 0.25.11
- '@esbuild/linux-ppc64': 0.25.11
- '@esbuild/linux-riscv64': 0.25.11
- '@esbuild/linux-s390x': 0.25.11
- '@esbuild/linux-x64': 0.25.11
- '@esbuild/netbsd-arm64': 0.25.11
- '@esbuild/netbsd-x64': 0.25.11
- '@esbuild/openbsd-arm64': 0.25.11
- '@esbuild/openbsd-x64': 0.25.11
- '@esbuild/openharmony-arm64': 0.25.11
- '@esbuild/sunos-x64': 0.25.11
- '@esbuild/win32-arm64': 0.25.11
- '@esbuild/win32-ia32': 0.25.11
- '@esbuild/win32-x64': 0.25.11
+ '@esbuild/aix-ppc64': 0.25.12
+ '@esbuild/android-arm': 0.25.12
+ '@esbuild/android-arm64': 0.25.12
+ '@esbuild/android-x64': 0.25.12
+ '@esbuild/darwin-arm64': 0.25.12
+ '@esbuild/darwin-x64': 0.25.12
+ '@esbuild/freebsd-arm64': 0.25.12
+ '@esbuild/freebsd-x64': 0.25.12
+ '@esbuild/linux-arm': 0.25.12
+ '@esbuild/linux-arm64': 0.25.12
+ '@esbuild/linux-ia32': 0.25.12
+ '@esbuild/linux-loong64': 0.25.12
+ '@esbuild/linux-mips64el': 0.25.12
+ '@esbuild/linux-ppc64': 0.25.12
+ '@esbuild/linux-riscv64': 0.25.12
+ '@esbuild/linux-s390x': 0.25.12
+ '@esbuild/linux-x64': 0.25.12
+ '@esbuild/netbsd-arm64': 0.25.12
+ '@esbuild/netbsd-x64': 0.25.12
+ '@esbuild/openbsd-arm64': 0.25.12
+ '@esbuild/openbsd-x64': 0.25.12
+ '@esbuild/openharmony-arm64': 0.25.12
+ '@esbuild/sunos-x64': 0.25.12
+ '@esbuild/win32-arm64': 0.25.12
+ '@esbuild/win32-ia32': 0.25.12
+ '@esbuild/win32-x64': 0.25.12
escalade@3.2.0: {}
@@ -4765,32 +4765,32 @@ snapshots:
rfdc@1.4.1: {}
- rollup@4.52.5:
+ rollup@4.53.3:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.52.5
- '@rollup/rollup-android-arm64': 4.52.5
- '@rollup/rollup-darwin-arm64': 4.52.5
- '@rollup/rollup-darwin-x64': 4.52.5
- '@rollup/rollup-freebsd-arm64': 4.52.5
- '@rollup/rollup-freebsd-x64': 4.52.5
- '@rollup/rollup-linux-arm-gnueabihf': 4.52.5
- '@rollup/rollup-linux-arm-musleabihf': 4.52.5
- '@rollup/rollup-linux-arm64-gnu': 4.52.5
- '@rollup/rollup-linux-arm64-musl': 4.52.5
- '@rollup/rollup-linux-loong64-gnu': 4.52.5
- '@rollup/rollup-linux-ppc64-gnu': 4.52.5
- '@rollup/rollup-linux-riscv64-gnu': 4.52.5
- '@rollup/rollup-linux-riscv64-musl': 4.52.5
- '@rollup/rollup-linux-s390x-gnu': 4.52.5
- '@rollup/rollup-linux-x64-gnu': 4.52.5
- '@rollup/rollup-linux-x64-musl': 4.52.5
- '@rollup/rollup-openharmony-arm64': 4.52.5
- '@rollup/rollup-win32-arm64-msvc': 4.52.5
- '@rollup/rollup-win32-ia32-msvc': 4.52.5
- '@rollup/rollup-win32-x64-gnu': 4.52.5
- '@rollup/rollup-win32-x64-msvc': 4.52.5
+ '@rollup/rollup-android-arm-eabi': 4.53.3
+ '@rollup/rollup-android-arm64': 4.53.3
+ '@rollup/rollup-darwin-arm64': 4.53.3
+ '@rollup/rollup-darwin-x64': 4.53.3
+ '@rollup/rollup-freebsd-arm64': 4.53.3
+ '@rollup/rollup-freebsd-x64': 4.53.3
+ '@rollup/rollup-linux-arm-gnueabihf': 4.53.3
+ '@rollup/rollup-linux-arm-musleabihf': 4.53.3
+ '@rollup/rollup-linux-arm64-gnu': 4.53.3
+ '@rollup/rollup-linux-arm64-musl': 4.53.3
+ '@rollup/rollup-linux-loong64-gnu': 4.53.3
+ '@rollup/rollup-linux-ppc64-gnu': 4.53.3
+ '@rollup/rollup-linux-riscv64-gnu': 4.53.3
+ '@rollup/rollup-linux-riscv64-musl': 4.53.3
+ '@rollup/rollup-linux-s390x-gnu': 4.53.3
+ '@rollup/rollup-linux-x64-gnu': 4.53.3
+ '@rollup/rollup-linux-x64-musl': 4.53.3
+ '@rollup/rollup-openharmony-arm64': 4.53.3
+ '@rollup/rollup-win32-arm64-msvc': 4.53.3
+ '@rollup/rollup-win32-ia32-msvc': 4.53.3
+ '@rollup/rollup-win32-x64-gnu': 4.53.3
+ '@rollup/rollup-win32-x64-msvc': 4.53.3
fsevents: 2.3.3
run-parallel@1.2.0:
@@ -4973,20 +4973,20 @@ snapshots:
dependencies:
global: 4.4.0
- vite-plugin-compression2@2.3.1(rollup@4.52.5):
+ vite-plugin-compression2@2.3.1(rollup@4.53.3):
dependencies:
- '@rollup/pluginutils': 5.3.0(rollup@4.52.5)
+ '@rollup/pluginutils': 5.3.0(rollup@4.53.3)
tar-mini: 0.2.0
transitivePeerDependencies:
- rollup
- vite@7.2.2(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0):
+ vite@7.2.4(@types/node@24.10.1)(terser@5.44.1)(yaml@2.7.0):
dependencies:
- esbuild: 0.25.11
+ esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.6
- rollup: 4.52.5
+ rollup: 4.53.3
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 24.10.1
diff --git a/go.mod b/go.mod
index abaeff87..e828455d 100644
--- a/go.mod
+++ b/go.mod
@@ -24,7 +24,7 @@ require (
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
- golang.org/x/crypto v0.44.0
+ golang.org/x/crypto v0.45.0
golang.org/x/image v0.33.0
golang.org/x/text v0.31.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
@@ -73,7 +73,7 @@ require (
go.etcd.io/bbolt v1.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect
- golang.org/x/net v0.46.0 // indirect
+ golang.org/x/net v0.47.0 // indirect
golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
diff --git a/go.sum b/go.sum
index 551f034e..443c885b 100644
--- a/go.sum
+++ b/go.sum
@@ -266,8 +266,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
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.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
-golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
+golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
+golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
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=
@@ -319,8 +319,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
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.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
-golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
+golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
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=
From a360f26979d57dd39cb19568844fffecaa5655f6 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 20 Nov 2025 18:54:40 +0100
Subject: [PATCH 043/120] chore(deps): update actions/checkout action to v6
(#5572)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
.github/workflows/ci.yaml | 10 +++++-----
.github/workflows/docs.yml | 4 ++--
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index b389be5f..846b08f8 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -13,7 +13,7 @@ jobs:
name: Lint Frontend
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
with:
package_json_file: "frontend/package.json"
@@ -31,7 +31,7 @@ jobs:
name: Lint Backend
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: "1.25.x"
@@ -43,7 +43,7 @@ jobs:
name: Test
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: "1.25.x"
@@ -53,7 +53,7 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-go@v6
@@ -77,7 +77,7 @@ jobs:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-go@v6
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 8eec9747..1f64177c 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Install Task
@@ -35,7 +35,7 @@ jobs:
timeout-minutes: 5
steps:
- name: Checkout
- uses: actions/checkout@v5
+ uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Install Task
From 43db19f8c886f97106fb10d55186a12cb3472d54 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Thu, 20 Nov 2025 18:57:20 +0100
Subject: [PATCH 044/120] chore(deps): update all non-major dependencies
(#5571)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/package.json | 2 +-
frontend/pnpm-lock.yaml | 8 ++++----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/frontend/package.json b/frontend/package.json
index ade91ff1..cda46e5e 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -71,5 +71,5 @@
"vite-plugin-compression2": "^2.3.1",
"vue-tsc": "^3.1.3"
},
- "packageManager": "pnpm@10.22.0+sha512.bf049efe995b28f527fd2b41ae0474ce29186f7edcb3bf545087bd61fbbebb2bf75362d1307fda09c2d288e1e499787ac12d4fcb617a974718a6051f2eee741c"
+ "packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b"
}
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 39576330..f3ebe665 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -43,7 +43,7 @@ importers:
version: 4.17.21
marked:
specifier: ^17.0.0
- version: 17.0.0
+ version: 17.0.1
material-icons:
specifier: ^1.13.14
version: 1.13.14
@@ -2003,8 +2003,8 @@ packages:
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
- marked@17.0.0:
- resolution: {integrity: sha512-KkDYEWEEiYJw/KC+DVm1zzlpMQSMIu6YRltkcCvwheCp8HWPXCk9JwOmHJKBlGfzcpzcIt6x3sMnTsRm/51oDg==}
+ marked@17.0.1:
+ resolution: {integrity: sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==}
engines: {node: '>= 20'}
hasBin: true
@@ -4558,7 +4558,7 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
- marked@17.0.0: {}
+ marked@17.0.1: {}
marks-pane@1.0.9: {}
From 88d1eecc4e9b4c5d7076ecb3c9971c272da287de Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 22 Nov 2025 07:57:55 +0100
Subject: [PATCH 045/120] chore(deps): update dependency eslint-plugin-vue to
v10.6.0 (#5573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/pnpm-lock.yaml | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index f3ebe665..3f4d405a 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -122,7 +122,7 @@ importers:
version: 10.2.0(eslint@9.39.1)(prettier@3.6.2)
'@vue/eslint-config-typescript':
specifier: ^14.6.0
- version: 14.6.0(eslint-plugin-vue@10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)
+ version: 14.6.0(eslint-plugin-vue@10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)
'@vue/tsconfig':
specifier: ^0.8.1
version: 0.8.1(typescript@5.9.3)(vue@3.5.24(typescript@5.9.3))
@@ -140,7 +140,7 @@ importers:
version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.39.1))(eslint@9.39.1)(prettier@3.6.2)
eslint-plugin-vue:
specifier: ^10.5.1
- version: 10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
+ version: 10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
postcss:
specifier: ^8.5.6
version: 8.5.6
@@ -1664,8 +1664,8 @@ packages:
eslint-config-prettier:
optional: true
- eslint-plugin-vue@10.5.1:
- resolution: {integrity: sha512-SbR9ZBUFKgvWAbq3RrdCtWaW0IKm6wwUiApxf3BVTNfqUIo4IQQmreMg2iHFJJ6C/0wss3LXURBJ1OwS/MhFcQ==}
+ eslint-plugin-vue@10.6.0:
+ resolution: {integrity: sha512-TsoFluWxOpsJlE/l2jJygLQLWBPJ3Qdkesv7tBIunICbTcG0dS1/NBw/Ol4tJw5kHWlAVds4lUmC29/vlPUcEQ==}
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
peerDependencies:
'@stylistic/eslint-plugin': ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0
@@ -2144,8 +2144,8 @@ packages:
resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==}
hasBin: true
- postcss-selector-parser@6.1.2:
- resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
+ postcss-selector-parser@7.1.0:
+ resolution: {integrity: sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==}
engines: {node: '>=4'}
postcss-value-parser@4.2.0:
@@ -3886,11 +3886,11 @@ snapshots:
transitivePeerDependencies:
- '@types/eslint'
- '@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)':
+ '@vue/eslint-config-typescript@14.6.0(eslint-plugin-vue@10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)))(eslint@9.39.1)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/utils': 8.37.0(eslint@9.39.1)(typescript@5.9.3)
eslint: 9.39.1
- eslint-plugin-vue: 10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
+ eslint-plugin-vue: 10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1))
fast-glob: 3.3.3
typescript-eslint: 8.37.0(eslint@9.39.1)(typescript@5.9.3)
vue-eslint-parser: 10.2.0(eslint@9.39.1)
@@ -4223,13 +4223,13 @@ snapshots:
optionalDependencies:
eslint-config-prettier: 10.1.8(eslint@9.39.1)
- eslint-plugin-vue@10.5.1(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)):
+ eslint-plugin-vue@10.6.0(@typescript-eslint/parser@8.37.0(eslint@9.39.1)(typescript@5.9.3))(eslint@9.39.1)(vue-eslint-parser@10.2.0(eslint@9.39.1)):
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
eslint: 9.39.1
natural-compare: 1.4.0
nth-check: 2.1.1
- postcss-selector-parser: 6.1.2
+ postcss-selector-parser: 7.1.0
semver: 7.7.3
vue-eslint-parser: 10.2.0(eslint@9.39.1)
xml-name-validator: 4.0.0
@@ -4673,7 +4673,7 @@ snapshots:
dependencies:
'@babel/runtime': 7.28.4
- postcss-selector-parser@6.1.2:
+ postcss-selector-parser@7.1.0:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
From 33deedf559b80436569282923662078ff2b6cee0 Mon Sep 17 00:00:00 2001
From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com>
Date: Sat, 22 Nov 2025 15:06:10 +0100
Subject: [PATCH 046/120] chore(deps): update dependency vue-i18n to v11.2.1
(#5574)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
---
frontend/pnpm-lock.yaml | 56 +++++++++++++++++++++++------------------
1 file changed, 31 insertions(+), 25 deletions(-)
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 3f4d405a..8b38a2a4 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -82,7 +82,7 @@ importers:
version: 4.5.5(@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3)))(@vueuse/integrations@14.0.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.24(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.24(typescript@5.9.3))
vue-i18n:
specifier: ^11.1.10
- version: 11.1.12(vue@3.5.24(typescript@5.9.3))
+ version: 11.2.1(vue@3.5.24(typescript@5.9.3))
vue-lazyload:
specifier: ^3.0.0
version: 3.0.0
@@ -98,7 +98,7 @@ importers:
devDependencies:
'@intlify/unplugin-vue-i18n':
specifier: ^11.0.1
- version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
+ version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
'@tsconfig/node24':
specifier: ^24.0.2
version: 24.0.3
@@ -887,18 +887,22 @@ packages:
vue-i18n:
optional: true
- '@intlify/core-base@11.1.12':
- resolution: {integrity: sha512-whh0trqRsSqVLNEUCwU59pyJZYpU8AmSWl8M3Jz2Mv5ESPP6kFh4juas2NpZ1iCvy7GlNRffUD1xr84gceimjg==}
+ '@intlify/core-base@11.2.1':
+ resolution: {integrity: sha512-2V1A4yaN9ElAnQ6ih3HHEc+jZ+sHV6BlQHjCsnIVlOotL5NCUgJElIxgUFiJs6zV4puoAq3hHuQIfWNp+J+8yQ==}
engines: {node: '>= 16'}
- '@intlify/message-compiler@11.1.12':
- resolution: {integrity: sha512-Fv9iQSJoJaXl4ZGkOCN1LDM3trzze0AS2zRz2EHLiwenwL6t0Ki9KySYlyr27yVOj5aVz0e55JePO+kELIvfdQ==}
+ '@intlify/message-compiler@11.2.1':
+ resolution: {integrity: sha512-J2454D3Agg3Kvgaj14gxTleJU8/H06Sisz7C2BwiHF0/i5Soyfb5ySpwn8GCL6yscDbOGj6xM+lUe6gO6BFQyg==}
engines: {node: '>= 16'}
'@intlify/shared@11.1.12':
resolution: {integrity: sha512-Om86EjuQtA69hdNj3GQec9ZC0L0vPSAnXzB3gP/gyJ7+mA7t06d9aOAiqMZ+xEOsumGP4eEBlfl8zF2LOTzf2A==}
engines: {node: '>= 16'}
+ '@intlify/shared@11.2.1':
+ resolution: {integrity: sha512-O67LZM4dbfr70WCsZLW+g+pIXdgQ66laLVd/FicW7iYgP/RuH0X1FDGSh+Hr9Gou/8TeldUE6KmTGdLwX2ufIA==}
+ engines: {node: '>= 16'}
+
'@intlify/unplugin-vue-i18n@11.0.1':
resolution: {integrity: sha512-nH5NJdNjy/lO6Ne8LDtZzv4SbpVsMhPE+LbvBDmMeIeJDiino8sOJN2QB3MXzTliYTnqe3aB9Fw5+LJ/XVaXCg==}
engines: {node: '>= 20'}
@@ -2492,8 +2496,8 @@ packages:
focus-trap: '>=7.2.0'
vue: '>=3.2.0'
- vue-i18n@11.1.12:
- resolution: {integrity: sha512-BnstPj3KLHLrsqbVU2UOrPmr0+Mv11bsUZG0PyCOzsawCivk8W00GMXHeVUWIDOgNaScCuZah47CZFE+Wnl8mw==}
+ vue-i18n@11.2.1:
+ resolution: {integrity: sha512-cc3Wx4eJZac9WMS8mxhfYiCipm9PBQ2Dz15piWYm7DwNcCehaKRgpolEdiqrjjT27T3Wijz3xJ7NeIc8ofIWAA==}
engines: {node: '>= 16'}
peerDependencies:
vue: ^3.0.0
@@ -3355,9 +3359,9 @@ snapshots:
'@humanwhocodes/retry@0.4.3': {}
- '@intlify/bundle-utils@11.0.1(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))':
+ '@intlify/bundle-utils@11.0.1(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))':
dependencies:
- '@intlify/message-compiler': 11.1.12
+ '@intlify/message-compiler': 11.2.1
'@intlify/shared': 11.1.12
acorn: 8.15.0
esbuild: 0.25.12
@@ -3367,26 +3371,28 @@ snapshots:
source-map-js: 1.2.1
yaml-eslint-parser: 1.2.3
optionalDependencies:
- vue-i18n: 11.1.12(vue@3.5.24(typescript@5.9.3))
+ vue-i18n: 11.2.1(vue@3.5.24(typescript@5.9.3))
- '@intlify/core-base@11.1.12':
+ '@intlify/core-base@11.2.1':
dependencies:
- '@intlify/message-compiler': 11.1.12
- '@intlify/shared': 11.1.12
+ '@intlify/message-compiler': 11.2.1
+ '@intlify/shared': 11.2.1
- '@intlify/message-compiler@11.1.12':
+ '@intlify/message-compiler@11.2.1':
dependencies:
- '@intlify/shared': 11.1.12
+ '@intlify/shared': 11.2.1
source-map-js: 1.2.1
'@intlify/shared@11.1.12': {}
- '@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
+ '@intlify/shared@11.2.1': {}
+
+ '@intlify/unplugin-vue-i18n@11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
dependencies:
'@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1)
- '@intlify/bundle-utils': 11.0.1(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))
+ '@intlify/bundle-utils': 11.0.1(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))
'@intlify/shared': 11.1.12
- '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
+ '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))
'@rollup/pluginutils': 5.3.0(rollup@4.53.3)
'@typescript-eslint/scope-manager': 8.46.4
'@typescript-eslint/typescript-estree': 8.46.4(typescript@5.9.3)
@@ -3397,7 +3403,7 @@ snapshots:
unplugin: 2.3.10
vue: 3.5.24(typescript@5.9.3)
optionalDependencies:
- vue-i18n: 11.1.12(vue@3.5.24(typescript@5.9.3))
+ vue-i18n: 11.2.1(vue@3.5.24(typescript@5.9.3))
transitivePeerDependencies:
- '@vue/compiler-dom'
- eslint
@@ -3405,14 +3411,14 @@ snapshots:
- supports-color
- typescript
- '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
+ '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.1.12)(@vue/compiler-dom@3.5.24)(vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)))(vue@3.5.24(typescript@5.9.3))':
dependencies:
'@babel/parser': 7.28.5
optionalDependencies:
'@intlify/shared': 11.1.12
'@vue/compiler-dom': 3.5.24
vue: 3.5.24(typescript@5.9.3)
- vue-i18n: 11.1.12(vue@3.5.24(typescript@5.9.3))
+ vue-i18n: 11.2.1(vue@3.5.24(typescript@5.9.3))
'@jridgewell/gen-mapping@0.3.13':
dependencies:
@@ -5015,10 +5021,10 @@ snapshots:
focus-trap: 7.6.2
vue: 3.5.24(typescript@5.9.3)
- vue-i18n@11.1.12(vue@3.5.24(typescript@5.9.3)):
+ vue-i18n@11.2.1(vue@3.5.24(typescript@5.9.3)):
dependencies:
- '@intlify/core-base': 11.1.12
- '@intlify/shared': 11.1.12
+ '@intlify/core-base': 11.2.1
+ '@intlify/shared': 11.2.1
'@vue/devtools-api': 6.6.4
vue: 3.5.24(typescript@5.9.3)
From 54306bdc8700fac489326ae81e28ac5db0580d13 Mon Sep 17 00:00:00 2001
From: "transifex-integration[bot]"
<43880903+transifex-integration[bot]@users.noreply.github.com>
Date: Sat, 22 Nov 2025 16:36:03 +0100
Subject: [PATCH 047/120] feat: Updates for project File Browser (#5566)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
---
frontend/src/i18n/ar.json | 1 +
frontend/src/i18n/bg.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/hr.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 +
30 files changed, 30 insertions(+)
diff --git a/frontend/src/i18n/ar.json b/frontend/src/i18n/ar.json
index ebf6a92b..5e736eaa 100644
--- a/frontend/src/i18n/ar.json
+++ b/frontend/src/i18n/ar.json
@@ -102,6 +102,7 @@
"username": "إسم المستخدم",
"usernameTaken": "إسم المستخدم غير متاح",
"wrongCredentials": "بيانات دخول خاطئة",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/bg.json b/frontend/src/i18n/bg.json
index 82fa6b1b..e71fa87b 100644
--- a/frontend/src/i18n/bg.json
+++ b/frontend/src/i18n/bg.json
@@ -102,6 +102,7 @@
"username": "Потребителско име",
"usernameTaken": "Потребителското име вече се използва",
"wrongCredentials": "Грешни потребителско име и/или парола",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "Бяхте разлогнати поради неактивност"
}
diff --git a/frontend/src/i18n/ca.json b/frontend/src/i18n/ca.json
index e895ca78..9c23e678 100644
--- a/frontend/src/i18n/ca.json
+++ b/frontend/src/i18n/ca.json
@@ -102,6 +102,7 @@
"username": "Usuari",
"usernameTaken": "Nom d'usuari no disponible",
"wrongCredentials": "Usuari i/o contrasenya incorrectes",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/cs.json b/frontend/src/i18n/cs.json
index 2d84ced7..ba0119fc 100644
--- a/frontend/src/i18n/cs.json
+++ b/frontend/src/i18n/cs.json
@@ -102,6 +102,7 @@
"username": "Uživatelské jméno",
"usernameTaken": "Uživatelské jméno již existuje",
"wrongCredentials": "Nesprávné přihlašovací údaje",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/de.json b/frontend/src/i18n/de.json
index 52cd2fc3..de34b6e2 100644
--- a/frontend/src/i18n/de.json
+++ b/frontend/src/i18n/de.json
@@ -102,6 +102,7 @@
"username": "Benutzername",
"usernameTaken": "Benutzername ist bereits vergeben",
"wrongCredentials": "Falsche Zugangsdaten",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/el.json b/frontend/src/i18n/el.json
index 0d98e90a..1826047c 100644
--- a/frontend/src/i18n/el.json
+++ b/frontend/src/i18n/el.json
@@ -102,6 +102,7 @@
"username": "Όνομα χρήστη",
"usernameTaken": "Το όνομα χρήστη χρησιμοποιείται ήδη",
"wrongCredentials": "Λάθος όνομα ή/και κωδικός πρόσβασης",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/es.json b/frontend/src/i18n/es.json
index 9d0b0b99..2ad3e6fd 100644
--- a/frontend/src/i18n/es.json
+++ b/frontend/src/i18n/es.json
@@ -102,6 +102,7 @@
"username": "Usuario",
"usernameTaken": "Nombre usuario no disponible",
"wrongCredentials": "Usuario y/o contraseña incorrectos",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/fa.json b/frontend/src/i18n/fa.json
index f3b5bc17..db619924 100644
--- a/frontend/src/i18n/fa.json
+++ b/frontend/src/i18n/fa.json
@@ -102,6 +102,7 @@
"username": "نام کاربری",
"usernameTaken": "نام کاربری تکراری",
"wrongCredentials": "خطا در اعتبارسنجی",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/fr.json b/frontend/src/i18n/fr.json
index 421d4cc4..b9bba59a 100644
--- a/frontend/src/i18n/fr.json
+++ b/frontend/src/i18n/fr.json
@@ -102,6 +102,7 @@
"username": "Utilisateur·ice",
"usernameTaken": "Le nom d'utilisateur·ice est déjà pris",
"wrongCredentials": "Identifiants incorrects !",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/he.json b/frontend/src/i18n/he.json
index d932b0ae..29bc6842 100644
--- a/frontend/src/i18n/he.json
+++ b/frontend/src/i18n/he.json
@@ -102,6 +102,7 @@
"username": "שם משתמש",
"usernameTaken": "שם המשתמש כבר קיים",
"wrongCredentials": "פרטי התחברות שגויים",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/hr.json b/frontend/src/i18n/hr.json
index 5c241daf..04bcfa2e 100644
--- a/frontend/src/i18n/hr.json
+++ b/frontend/src/i18n/hr.json
@@ -102,6 +102,7 @@
"username": "Korisničko ime",
"usernameTaken": "Korisničko ime zauzeto",
"wrongCredentials": "Neispravno korisničko ime/lozinka",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "Odjavljeni ste zbog neaktivnosti."
}
diff --git a/frontend/src/i18n/hu.json b/frontend/src/i18n/hu.json
index 79396c72..565fb076 100644
--- a/frontend/src/i18n/hu.json
+++ b/frontend/src/i18n/hu.json
@@ -102,6 +102,7 @@
"username": "Felhasználói név",
"usernameTaken": "A felhasználói név már foglalt",
"wrongCredentials": "Hibás hitelesítő adatok",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/is.json b/frontend/src/i18n/is.json
index e67a4bab..ac114dc9 100644
--- a/frontend/src/i18n/is.json
+++ b/frontend/src/i18n/is.json
@@ -102,6 +102,7 @@
"username": "Notendanafn",
"usernameTaken": "Þetta norendanafn er þegar í notkun",
"wrongCredentials": "Rangar notendaupplýsingar",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/it.json b/frontend/src/i18n/it.json
index 7e04c40f..50170b70 100644
--- a/frontend/src/i18n/it.json
+++ b/frontend/src/i18n/it.json
@@ -102,6 +102,7 @@
"username": "Nome utente",
"usernameTaken": "Username già usato",
"wrongCredentials": "Credenziali errate",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/ja.json b/frontend/src/i18n/ja.json
index bda66d09..870d38c7 100644
--- a/frontend/src/i18n/ja.json
+++ b/frontend/src/i18n/ja.json
@@ -102,6 +102,7 @@
"username": "ユーザー名",
"usernameTaken": "ユーザー名はすでに取得されています",
"wrongCredentials": "ユーザー名またはパスワードが間違っています",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/ko.json b/frontend/src/i18n/ko.json
index 498c0812..cae58cae 100644
--- a/frontend/src/i18n/ko.json
+++ b/frontend/src/i18n/ko.json
@@ -102,6 +102,7 @@
"username": "사용자 이름",
"usernameTaken": "사용자 이름이 존재합니다",
"wrongCredentials": "사용자 이름 또는 비밀번호를 확인하십시오",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/nl-be.json b/frontend/src/i18n/nl-be.json
index b587a79b..83bf3ce0 100644
--- a/frontend/src/i18n/nl-be.json
+++ b/frontend/src/i18n/nl-be.json
@@ -102,6 +102,7 @@
"username": "Gebruikersnaam",
"usernameTaken": "Gebruikersnaam reeds in gebruik",
"wrongCredentials": "Verkeerde inloggegevens",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/no.json b/frontend/src/i18n/no.json
index b7a885eb..918ef19f 100644
--- a/frontend/src/i18n/no.json
+++ b/frontend/src/i18n/no.json
@@ -102,6 +102,7 @@
"username": "Brukernavn",
"usernameTaken": "Brukernavn er allerede i bruk",
"wrongCredentials": "Feil legitimasjon",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "Du har blitt logget ut på grunn av inaktivitet"
}
diff --git a/frontend/src/i18n/pl.json b/frontend/src/i18n/pl.json
index e34c1c07..17790935 100644
--- a/frontend/src/i18n/pl.json
+++ b/frontend/src/i18n/pl.json
@@ -102,6 +102,7 @@
"username": "Nazwa użytkownika",
"usernameTaken": "Ta nazwa użytkownika jest zajęta",
"wrongCredentials": "Błędne dane logowania",
+ "passwordTooShort": "Wymagana minimalna liczba znaków hasła: {min}",
"logout_reasons": {
"inactivity": "Wylogowano z powodu braku aktywności."
}
diff --git a/frontend/src/i18n/pt-br.json b/frontend/src/i18n/pt-br.json
index 54b8234b..f6ef04e6 100644
--- a/frontend/src/i18n/pt-br.json
+++ b/frontend/src/i18n/pt-br.json
@@ -102,6 +102,7 @@
"username": "Nome do usuário",
"usernameTaken": "Nome de usuário já existe",
"wrongCredentials": "Ops! Dados incorretos.",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/pt.json b/frontend/src/i18n/pt.json
index fb44edba..38e5f89b 100644
--- a/frontend/src/i18n/pt.json
+++ b/frontend/src/i18n/pt.json
@@ -102,6 +102,7 @@
"username": "Nome de utilizador",
"usernameTaken": "O nome de utilizador já está registado",
"wrongCredentials": "Dados errados",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/ro.json b/frontend/src/i18n/ro.json
index 92c40d20..a2072b2e 100644
--- a/frontend/src/i18n/ro.json
+++ b/frontend/src/i18n/ro.json
@@ -102,6 +102,7 @@
"username": "Utilizator",
"usernameTaken": "Utilizatorul există",
"wrongCredentials": "Informații greșite",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/ru.json b/frontend/src/i18n/ru.json
index b3307f45..1cadeb3b 100644
--- a/frontend/src/i18n/ru.json
+++ b/frontend/src/i18n/ru.json
@@ -102,6 +102,7 @@
"username": "Имя пользователя",
"usernameTaken": "Данное имя пользователя уже занято",
"wrongCredentials": "Неверные данные",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/sk.json b/frontend/src/i18n/sk.json
index 95a34486..9cb1c941 100644
--- a/frontend/src/i18n/sk.json
+++ b/frontend/src/i18n/sk.json
@@ -102,6 +102,7 @@
"username": "Používateľské meno",
"usernameTaken": "Meno je už obsadené",
"wrongCredentials": "Nesprávne prihlasovacie údaje",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "Boli ste odhlásení z dôvodu nečinnosti."
}
diff --git a/frontend/src/i18n/sv-se.json b/frontend/src/i18n/sv-se.json
index e4e89911..4cced166 100644
--- a/frontend/src/i18n/sv-se.json
+++ b/frontend/src/i18n/sv-se.json
@@ -102,6 +102,7 @@
"username": "Användarnamn",
"usernameTaken": "Användarnamn upptaget",
"wrongCredentials": "Fel inloggning",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "Du har blivit utloggad på grund av inaktivitet."
}
diff --git a/frontend/src/i18n/tr.json b/frontend/src/i18n/tr.json
index 6d3fbc5c..144cf73d 100644
--- a/frontend/src/i18n/tr.json
+++ b/frontend/src/i18n/tr.json
@@ -102,6 +102,7 @@
"username": "Kullanıcı adı",
"usernameTaken": "Kullanıcı adı mevcut",
"wrongCredentials": "Yanlış hesap bilgileri",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/uk.json b/frontend/src/i18n/uk.json
index 3c78b228..465c0364 100644
--- a/frontend/src/i18n/uk.json
+++ b/frontend/src/i18n/uk.json
@@ -102,6 +102,7 @@
"username": "Ім'я користувача",
"usernameTaken": "Ім'я користувача вже використовується",
"wrongCredentials": "Неправильне ім'я користувача або пароль",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/vi.json b/frontend/src/i18n/vi.json
index aa2a5279..77e7655e 100644
--- a/frontend/src/i18n/vi.json
+++ b/frontend/src/i18n/vi.json
@@ -102,6 +102,7 @@
"username": "Tên người dùng",
"usernameTaken": "Tên người dùng đã tồn tại",
"wrongCredentials": "Thông tin đăng nhập không đúng",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/zh-cn.json b/frontend/src/i18n/zh-cn.json
index def97e9a..fd927ce3 100644
--- a/frontend/src/i18n/zh-cn.json
+++ b/frontend/src/i18n/zh-cn.json
@@ -102,6 +102,7 @@
"username": "用户名",
"usernameTaken": "用户名已经被使用",
"wrongCredentials": "用户名或密码错误",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
diff --git a/frontend/src/i18n/zh-tw.json b/frontend/src/i18n/zh-tw.json
index 4644ad90..36828522 100644
--- a/frontend/src/i18n/zh-tw.json
+++ b/frontend/src/i18n/zh-tw.json
@@ -102,6 +102,7 @@
"username": "帳號",
"usernameTaken": "用戶名已存在",
"wrongCredentials": "帳號或密碼錯誤",
+ "passwordTooShort": "Password must be at least {min} characters",
"logout_reasons": {
"inactivity": "You have been logged out due to inactivity."
}
From d48f5665d6975c4cbbdf9be20dc2e0106db02f01 Mon Sep 17 00:00:00 2001
From: Kosmos <2153183+kosmosac@users.noreply.github.com>
Date: Sat, 22 Nov 2025 17:07:10 +0100
Subject: [PATCH 048/120] feat: add "copy download link to clipboard" button to
Share prompt (#5173)
Co-authored-by: Henrique Dias
---
frontend/src/components/prompts/Share.vue | 40 +++++++++++++++++++----
frontend/src/css/styles.css | 5 +--
2 files changed, 36 insertions(+), 9 deletions(-)
diff --git a/frontend/src/components/prompts/Share.vue b/frontend/src/components/prompts/Share.vue
index 3ce2b1fd..282902fb 100644
--- a/frontend/src/components/prompts/Share.vue
+++ b/frontend/src/components/prompts/Share.vue
@@ -12,6 +12,7 @@
{{ $t("settings.shareDuration") }} |
|
|
+ |
@@ -24,7 +25,7 @@
|
|
+
+
+ |
|