diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 31ecc905cc..f0baf26aa8 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 32d8040465..f5b0911ab4 100644 --- a/frontend/src/views/settings/Profile.vue +++ b/frontend/src/views/settings/Profile.vue @@ -6,6 +6,7 @@
+

{{ $t('settings.hideDotfiles') }}

{{ $t('settings.language') }}

@@ -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 5c47fcf153..4145ceb290 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 2106d4c556..1bdafe3f58 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 548332a4bd..d8a7f9678d 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 0000000000..570f921f3d --- /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 b08296558d..b9993fbbce 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 1df0a89b8c..5aba507dae 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.