diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json
index 31ecc905..f0baf26a 100644
--- a/frontend/src/i18n/en.json
+++ b/frontend/src/i18n/en.json
@@ -32,7 +32,8 @@
"toggleSidebar": "Toggle sidebar",
"update": "Update",
"upload": "Upload",
- "permalink": "Get Permanent Link"
+ "permalink": "Get Permanent Link",
+ "hideDotfiles": "Hide dotfiles"
},
"success": {
"linkCopied": "Link copied!"
@@ -188,7 +189,8 @@
"execute": "Execute commands",
"rename": "Rename or move files and directories",
"share": "Share files"
- }
+ },
+ "hideDotfiles": "Hide dotfiles"
},
"sidebar": {
"help": "Help",
@@ -244,4 +246,4 @@
"downloadFile": "Download File",
"downloadFolder": "Download Folder"
}
-}
\ No newline at end of file
+}
diff --git a/frontend/src/views/settings/Profile.vue b/frontend/src/views/settings/Profile.vue
index 32d80404..f5b0911a 100644
--- a/frontend/src/views/settings/Profile.vue
+++ b/frontend/src/views/settings/Profile.vue
@@ -6,6 +6,7 @@
@@ -67,6 +68,7 @@ export default {
},
created () {
this.locale = this.user.locale
+ this.hideDotfiles = this.user.hideDotfiles
},
methods: {
...mapMutations([ 'updateUser' ]),
@@ -90,8 +92,8 @@ export default {
event.preventDefault()
try {
- const data = { id: this.user.id, locale: this.locale }
- await api.update(data, ['locale'])
+ const data = { id: this.user.id, locale: this.locale, hideDotfiles: this.hideDotfiles }
+ await api.update(data, ['locale', 'hideDotfiles'])
this.updateUser(data)
this.$showSuccess(this.$t('settings.settingsUpdated'))
} catch (e) {
diff --git a/http/auth.go b/http/auth.go
index 5c47fcf1..4145ceb2 100644
--- a/http/auth.go
+++ b/http/auth.go
@@ -26,6 +26,7 @@ type userInfo struct {
Perm users.Permissions `json:"perm"`
Commands []string `json:"commands"`
LockPassword bool `json:"lockPassword"`
+ HideDotfiles bool `json:"hideDotfiles"`
}
type authToken struct {
@@ -175,6 +176,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
Perm: user.Perm,
LockPassword: user.LockPassword,
Commands: user.Commands,
+ HideDotfiles: user.HideDotfiles,
},
StandardClaims: jwt.StandardClaims{
IssuedAt: time.Now().Unix(),
diff --git a/http/data.go b/http/data.go
index 2106d4c5..1bdafe3f 100644
--- a/http/data.go
+++ b/http/data.go
@@ -7,6 +7,7 @@ import (
"github.com/tomasen/realip"
+ "github.com/filebrowser/filebrowser/v2/rules"
"github.com/filebrowser/filebrowser/v2/runner"
"github.com/filebrowser/filebrowser/v2/settings"
"github.com/filebrowser/filebrowser/v2/storage"
@@ -26,6 +27,10 @@ type data struct {
// Check implements rules.Checker.
func (d *data) Check(path string) bool {
+ if d.user.HideDotfiles && rules.MatchHidden(path) {
+ return false
+ }
+
allow := true
for _, rule := range d.settings.Rules {
if rule.Matches(path) {
diff --git a/rules/rules.go b/rules/rules.go
index 548332a4..d8a7f967 100644
--- a/rules/rules.go
+++ b/rules/rules.go
@@ -1,6 +1,7 @@
package rules
import (
+ "path/filepath"
"regexp"
"strings"
)
@@ -18,6 +19,12 @@ type Rule struct {
Regexp *Regexp `json:"regexp"`
}
+// MatchHidden matches paths with a basename
+// that begins with a dot.
+func MatchHidden(path string) bool {
+ return strings.HasPrefix(filepath.Base(path), ".")
+}
+
// Matches matches a path against a rule.
func (r *Rule) Matches(path string) bool {
if r.Regex {
diff --git a/rules/rules_test.go b/rules/rules_test.go
new file mode 100644
index 00000000..570f921f
--- /dev/null
+++ b/rules/rules_test.go
@@ -0,0 +1,23 @@
+package rules
+
+import "testing"
+
+func TestMatchHidden(t *testing.T) {
+ cases := map[string]bool{
+ "/": false,
+ "/src": false,
+ "/src/": false,
+ "/.circleci": true,
+ "/a/b/c/.docker.json": true,
+ ".docker.json": true,
+ "Dockerfile": false,
+ "/Dockerfile": false,
+ }
+
+ for path, want := range cases {
+ got := MatchHidden(path)
+ if got != want {
+ t.Errorf("MatchHidden(%s)=%v; want %v", path, got, want)
+ }
+ }
+}
diff --git a/settings/defaults.go b/settings/defaults.go
index b0829655..b9993fbb 100644
--- a/settings/defaults.go
+++ b/settings/defaults.go
@@ -8,12 +8,13 @@ import (
// UserDefaults is a type that holds the default values
// for some fields on User.
type UserDefaults struct {
- Scope string `json:"scope"`
- Locale string `json:"locale"`
- ViewMode users.ViewMode `json:"viewMode"`
- Sorting files.Sorting `json:"sorting"`
- Perm users.Permissions `json:"perm"`
- Commands []string `json:"commands"`
+ Scope string `json:"scope"`
+ Locale string `json:"locale"`
+ ViewMode users.ViewMode `json:"viewMode"`
+ Sorting files.Sorting `json:"sorting"`
+ Perm users.Permissions `json:"perm"`
+ Commands []string `json:"commands"`
+ HideDotfiles bool `json:"hideDotfiles"`
}
// Apply applies the default options to a user.
@@ -24,4 +25,5 @@ func (d *UserDefaults) Apply(u *users.User) {
u.Perm = d.Perm
u.Sorting = d.Sorting
u.Commands = d.Commands
+ u.HideDotfiles = d.HideDotfiles
}
diff --git a/users/users.go b/users/users.go
index 1df0a89b..5aba507d 100644
--- a/users/users.go
+++ b/users/users.go
@@ -33,6 +33,7 @@ type User struct {
Sorting files.Sorting `json:"sorting"`
Fs afero.Fs `json:"-" yaml:"-"`
Rules []rules.Rule `json:"rules"`
+ HideDotfiles bool `json:"hideDotfiles"`
}
// GetRules implements rules.Provider.