Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Graham Steffaniak <graham.steffaniak@autodesk.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
parent
ac544738a2
commit
398ac49aa9
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -2,15 +2,18 @@
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version).
|
All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version).
|
||||||
|
|
||||||
|
## v0.2.3
|
||||||
|
|
||||||
|
- Feature: token expiration time now configurable
|
||||||
|
- FIX: Hidden files are still directly accessible. (https://github.com/filebrowser/filebrowser/issues/2698)
|
||||||
|
- FIX: search/user context bug
|
||||||
|
|
||||||
## v0.2.2
|
## v0.2.2
|
||||||
|
|
||||||
- **Major Indexing Changes:**
|
- CHG: **Speed:** (0m57s) - Decreased by 78% compared to the previous release.
|
||||||
- **Speed:** (0m57s) - Decreased by 78% compared to the previous release.
|
- CHG: **Memory Usage:** (41MB) - Reduced by 45% compared to the previous release.
|
||||||
- **Memory Usage:** (41MB) - Reduced by 45% compared to the previous release.
|
- Feature: Now utilizes the index for file browser listings!
|
||||||
- Now utilizes the index for file browser listings!
|
- FIX: Editor issues fixed on save and themes.
|
||||||
- **[Work in Progress]** Hidden files are still directly accessible.
|
|
||||||
- **[Work in Progress]** Editor issues fixed on save and themes.
|
|
||||||
- **[Work in Progress]** `running-config.yaml` gets updated when settings change, ensuring that running settings are up to date.
|
|
||||||
|
|
||||||
## v0.2.1
|
## v0.2.1
|
||||||
|
|
||||||
|
|
|
@ -119,8 +119,10 @@ func (si *Index) InsertFiles(path string) {
|
||||||
buffer := bytes.Buffer{}
|
buffer := bytes.Buffer{}
|
||||||
|
|
||||||
for _, f := range si.GetQuickList() {
|
for _, f := range si.GetQuickList() {
|
||||||
buffer.WriteString(f.Name + ";")
|
if !f.IsDir {
|
||||||
si.UpdateCount("files")
|
buffer.WriteString(f.Name + ";")
|
||||||
|
si.UpdateCount("files")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Use GetMetadataInfo and SetFileMetadata for safer read and write operations
|
// Use GetMetadataInfo and SetFileMetadata for safer read and write operations
|
||||||
subDirectory.Files = buffer.String()
|
subDirectory.Files = buffer.String()
|
||||||
|
|
|
@ -16,16 +16,15 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
|
func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
|
||||||
if scope == "" {
|
// Remove slashes
|
||||||
scope = "/"
|
scope = strings.TrimLeft(scope, "/")
|
||||||
}
|
scope = strings.TrimRight(scope, "/")
|
||||||
runningHash := generateRandomHash(4)
|
runningHash := generateRandomHash(4)
|
||||||
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
|
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
|
||||||
searchOptions := ParseSearch(search)
|
searchOptions := ParseSearch(search)
|
||||||
fileListTypes := make(map[string]map[string]bool)
|
fileListTypes := make(map[string]map[string]bool)
|
||||||
matching := []string{}
|
matching := []string{}
|
||||||
count := 0
|
count := 0
|
||||||
|
|
||||||
for _, searchTerm := range searchOptions.Terms {
|
for _, searchTerm := range searchOptions.Terms {
|
||||||
if searchTerm == "" {
|
if searchTerm == "" {
|
||||||
continue
|
continue
|
||||||
|
@ -46,7 +45,6 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
|
||||||
if pathName == "" {
|
if pathName == "" {
|
||||||
continue // path not matched
|
continue // path not matched
|
||||||
}
|
}
|
||||||
|
|
||||||
fileTypes := map[string]bool{}
|
fileTypes := map[string]bool{}
|
||||||
matches, fileType := containsSearchTerm(dirName, searchTerm, *searchOptions, isDir, fileTypes)
|
matches, fileType := containsSearchTerm(dirName, searchTerm, *searchOptions, isDir, fileTypes)
|
||||||
if matches {
|
if matches {
|
||||||
|
@ -74,7 +72,6 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
|
||||||
if !matches {
|
if !matches {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
fileListTypes[fullName] = fileType
|
fileListTypes[fullName] = fileType
|
||||||
matching = append(matching, fullName)
|
matching = append(matching, fullName)
|
||||||
count++
|
count++
|
||||||
|
@ -91,11 +88,11 @@ func (si *Index) Search(search string, scope string, sourceSession string) ([]st
|
||||||
}
|
}
|
||||||
|
|
||||||
func scopedPathNameFilter(pathName string, scope string, isDir bool) string {
|
func scopedPathNameFilter(pathName string, scope string, isDir bool) string {
|
||||||
scope = strings.TrimPrefix(scope, "/")
|
pathName = strings.TrimLeft(pathName, "/")
|
||||||
pathName = strings.TrimPrefix(pathName, "/")
|
pathName = strings.TrimRight(pathName, "/")
|
||||||
pathName = strings.TrimSuffix(pathName, "/")
|
if strings.HasPrefix(pathName, scope) || scope == "" {
|
||||||
if strings.HasPrefix(pathName, scope) {
|
|
||||||
pathName = strings.TrimPrefix(pathName, scope)
|
pathName = strings.TrimPrefix(pathName, scope)
|
||||||
|
pathName = strings.TrimLeft(pathName, "/")
|
||||||
if isDir {
|
if isDir {
|
||||||
pathName = pathName + "/"
|
pathName = pathName + "/"
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,25 +163,38 @@ func TestSearchIndexes(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_scopedPathNameFilter(t *testing.T) {
|
func Test_scopedPathNameFilter(t *testing.T) {
|
||||||
type args struct {
|
|
||||||
pathName string
|
|
||||||
scope string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args struct {
|
||||||
|
pathName string
|
||||||
|
scope string
|
||||||
|
isDir bool // Assuming isDir should be included in args
|
||||||
|
}
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
// TODO: Add test cases.
|
{
|
||||||
|
name: "scope test",
|
||||||
|
args: struct {
|
||||||
|
pathName string
|
||||||
|
scope string
|
||||||
|
isDir bool
|
||||||
|
}{
|
||||||
|
pathName: "/",
|
||||||
|
scope: "/",
|
||||||
|
isDir: false,
|
||||||
|
},
|
||||||
|
want: "", // Update this with the expected result
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := scopedPathNameFilter(tt.args.pathName, tt.args.scope, false); got != tt.want {
|
if got := scopedPathNameFilter(tt.args.pathName, tt.args.scope, tt.args.isDir); got != tt.want {
|
||||||
t.Errorf("scopedPathNameFilter() = %v, want %v", got, tt.want)
|
t.Errorf("scopedPathNameFilter() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_isDoc(t *testing.T) {
|
func Test_isDoc(t *testing.T) {
|
||||||
type args struct {
|
type args struct {
|
||||||
extension string
|
extension string
|
||||||
|
|
|
@ -19,9 +19,9 @@ require (
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||||
golang.org/x/crypto v0.14.0
|
golang.org/x/crypto v0.17.0
|
||||||
golang.org/x/image v0.12.0
|
golang.org/x/image v0.12.0
|
||||||
golang.org/x/text v0.13.0
|
golang.org/x/text v0.14.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -49,7 +49,7 @@ require (
|
||||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||||
go.etcd.io/bbolt v1.3.4 // indirect
|
go.etcd.io/bbolt v1.3.4 // indirect
|
||||||
golang.org/x/net v0.17.0 // indirect
|
golang.org/x/net v0.17.0 // indirect
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
golang.org/x/sys v0.15.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
|
@ -280,8 +280,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -426,8 +426,8 @@ golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
@ -440,8 +440,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
|
||||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|
|
@ -2,6 +2,7 @@ package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -16,10 +17,6 @@ import (
|
||||||
"github.com/gtsteffaniak/filebrowser/users"
|
"github.com/gtsteffaniak/filebrowser/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
TokenExpirationTime = time.Hour * 2
|
|
||||||
)
|
|
||||||
|
|
||||||
type authToken struct {
|
type authToken struct {
|
||||||
User users.User `json:"user"`
|
User users.User `json:"user"`
|
||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
|
@ -158,11 +155,16 @@ var renewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data
|
||||||
})
|
})
|
||||||
|
|
||||||
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) {
|
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) {
|
||||||
|
duration, err := time.ParseDuration(settings.Config.Auth.TokenExpirationTime)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error parsing duration:", err)
|
||||||
|
duration = time.Hour * 2
|
||||||
|
}
|
||||||
claims := &authToken{
|
claims := &authToken{
|
||||||
User: *user,
|
User: *user,
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpirationTime)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(duration)),
|
||||||
Issuer: "File Browser",
|
Issuer: "File Browser",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/tomasen/realip"
|
"github.com/tomasen/realip"
|
||||||
|
|
||||||
"github.com/gtsteffaniak/filebrowser/rules"
|
|
||||||
"github.com/gtsteffaniak/filebrowser/runner"
|
"github.com/gtsteffaniak/filebrowser/runner"
|
||||||
"github.com/gtsteffaniak/filebrowser/settings"
|
"github.com/gtsteffaniak/filebrowser/settings"
|
||||||
"github.com/gtsteffaniak/filebrowser/storage"
|
"github.com/gtsteffaniak/filebrowser/storage"
|
||||||
|
@ -27,9 +26,6 @@ type data struct {
|
||||||
|
|
||||||
// Check implements rules.Checker.
|
// Check implements rules.Checker.
|
||||||
func (d *data) Check(path string) bool {
|
func (d *data) Check(path string) bool {
|
||||||
if d.user.HideDotfiles && rules.MatchHidden(path) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
allow := true
|
allow := true
|
||||||
for _, rule := range d.settings.Rules {
|
for _, rule := range d.settings.Rules {
|
||||||
|
|
|
@ -16,7 +16,6 @@ var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *dat
|
||||||
userScope := r.Header.Get("UserScope")
|
userScope := r.Header.Get("UserScope")
|
||||||
index := files.GetIndex(settings.Config.Server.Root)
|
index := files.GetIndex(settings.Config.Server.Root)
|
||||||
combinedScope := strings.TrimPrefix(userScope+r.URL.Path, ".")
|
combinedScope := strings.TrimPrefix(userScope+r.URL.Path, ".")
|
||||||
combinedScope = strings.TrimPrefix(combinedScope, "/")
|
|
||||||
results, fileTypes := index.Search(query, combinedScope, sessionId)
|
results, fileTypes := index.Search(query, combinedScope, sessionId)
|
||||||
for _, path := range results {
|
for _, path := range results {
|
||||||
responseObj := map[string]interface{}{
|
responseObj := map[string]interface{}{
|
||||||
|
|
|
@ -60,10 +60,11 @@ func setDefaults() Settings {
|
||||||
Root: "/srv",
|
Root: "/srv",
|
||||||
},
|
},
|
||||||
Auth: Auth{
|
Auth: Auth{
|
||||||
AdminUsername: "admin",
|
TokenExpirationTime: "2h",
|
||||||
AdminPassword: "admin",
|
AdminUsername: "admin",
|
||||||
Method: "password",
|
AdminPassword: "admin",
|
||||||
Signup: false,
|
Method: "password",
|
||||||
|
Signup: false,
|
||||||
Recaptcha: Recaptcha{
|
Recaptcha: Recaptcha{
|
||||||
Host: "",
|
Host: "",
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,15 +17,16 @@ type Settings struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Auth struct {
|
type Auth struct {
|
||||||
Recaptcha Recaptcha `json:"recaptcha"`
|
TokenExpirationTime string `json:"tokenExpirationTime"`
|
||||||
Header string `json:"header"`
|
Recaptcha Recaptcha `json:"recaptcha"`
|
||||||
Method string `json:"method"`
|
Header string `json:"header"`
|
||||||
Command string `json:"command"`
|
Method string `json:"method"`
|
||||||
Signup bool `json:"signup"`
|
Command string `json:"command"`
|
||||||
Shell string `json:"shell"`
|
Signup bool `json:"signup"`
|
||||||
AdminUsername string `json:"adminUsername"`
|
Shell string `json:"shell"`
|
||||||
AdminPassword string `json:"adminPassword"`
|
AdminUsername string `json:"adminUsername"`
|
||||||
Key []byte `json:"key"`
|
AdminPassword string `json:"adminPassword"`
|
||||||
|
Key []byte `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Recaptcha struct {
|
type Recaptcha struct {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package version
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Version is the current File Browser version.
|
// Version is the current File Browser version.
|
||||||
Version = "(0.2.2)"
|
Version = "(0.2.3)"
|
||||||
// CommitSHA is the commmit sha.
|
// CommitSHA is the commmit sha.
|
||||||
CommitSHA = "(unknown)"
|
CommitSHA = "(unknown)"
|
||||||
)
|
)
|
||||||
|
|
|
@ -31,6 +31,7 @@ auth:
|
||||||
host: ""
|
host: ""
|
||||||
key: ""
|
key: ""
|
||||||
secret: ""
|
secret: ""
|
||||||
|
tokenExpirationTime: 2h
|
||||||
header: ""
|
header: ""
|
||||||
method: json
|
method: json
|
||||||
command: ""
|
command: ""
|
||||||
|
|
|
@ -1045,9 +1045,9 @@
|
||||||
},
|
},
|
||||||
"node_modules/@vue/vue-loader-v15": {
|
"node_modules/@vue/vue-loader-v15": {
|
||||||
"name": "vue-loader",
|
"name": "vue-loader",
|
||||||
"version": "15.10.2",
|
"version": "15.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.11.1.tgz",
|
||||||
"integrity": "sha512-ndeSe/8KQc/nlA7TJ+OBhv2qalmj1s+uBs7yHDRFaAXscFTApBzY9F1jES3bautmgWjDlDct0fw8rPuySDLwxw==",
|
"integrity": "sha512-0iw4VchYLePqJfJu9s62ACWUXeSqM30SQqlIftbYWM3C+jpPcEHKSPUZBLjSF9au4HTHQ/naF6OGnO3Q/qGR3Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/component-compiler-utils": "^3.1.0",
|
"@vue/component-compiler-utils": "^3.1.0",
|
||||||
|
@ -5341,9 +5341,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nanoid": {
|
"node_modules/nanoid": {
|
||||||
"version": "3.3.6",
|
"version": "3.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
@ -5896,9 +5896,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
"version": "8.4.29",
|
"version": "8.4.32",
|
||||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz",
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz",
|
||||||
"integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==",
|
"integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
@ -5914,7 +5914,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.6",
|
"nanoid": "^3.3.7",
|
||||||
"picocolors": "^1.0.0",
|
"picocolors": "^1.0.0",
|
||||||
"source-map-js": "^1.0.2"
|
"source-map-js": "^1.0.2"
|
||||||
},
|
},
|
||||||
|
|
|
@ -43,11 +43,6 @@
|
||||||
"eslint-plugin-vue": "^9.17.0",
|
"eslint-plugin-vue": "^9.17.0",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.10"
|
||||||
},
|
},
|
||||||
"postcss": {
|
|
||||||
"plugins": {
|
|
||||||
"autoprefixer": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result">
|
<div v-if="isMobile && active" id="result" :class="{ hidden: !active }" ref="result">
|
||||||
<div id="result-list">
|
<div id="result-list">
|
||||||
<div class="button" style="width: 100%">
|
<div class="button" style="width: 100%">
|
||||||
Search Context: {{ this.searchContext }}
|
Search Context: {{ getContext }}
|
||||||
</div>
|
</div>
|
||||||
<ul v-show="results.length > 0">
|
<ul v-show="results.length > 0">
|
||||||
<li
|
<li
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="!isMobile && active" id="result-desktop" ref="result">
|
<div v-show="!isMobile && active" id="result-desktop" ref="result">
|
||||||
<div class="searchContext">Search Context: {{ this.searchContext }}</div>
|
<div class="searchContext">Search Context: {{ getContext }}</div>
|
||||||
<div id="result-list">
|
<div id="result-list">
|
||||||
<template>
|
<template>
|
||||||
<p v-show="isEmpty && isRunning" id="renew">
|
<p v-show="isEmpty && isRunning" id="renew">
|
||||||
|
@ -535,7 +535,6 @@ export default {
|
||||||
name: "search",
|
name: "search",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
searchContext: "./",
|
|
||||||
largerThan: "",
|
largerThan: "",
|
||||||
smallerThan: "",
|
smallerThan: "",
|
||||||
noneMessage: "Start typing 3 or more characters to begin searching.",
|
noneMessage: "Start typing 3 or more characters to begin searching.",
|
||||||
|
@ -632,10 +631,16 @@ export default {
|
||||||
searchHelp() {
|
searchHelp() {
|
||||||
return this.showHelp;
|
return this.showHelp;
|
||||||
},
|
},
|
||||||
|
getContext() {
|
||||||
|
let path = this.$route.path
|
||||||
|
path = path.slice(1);
|
||||||
|
path = "./" + path.substring(path.indexOf("/") + 1);
|
||||||
|
path = path.replace(/\/+$/, "") + "/";
|
||||||
|
return path
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener("resize", this.handleResize);
|
window.addEventListener("resize", this.handleResize);
|
||||||
this.searchContext = this.getContext(this.$route.path)
|
|
||||||
this.handleResize(); // Call this once to set the initial width
|
this.handleResize(); // Call this once to set the initial width
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -647,19 +652,15 @@ export default {
|
||||||
await this.$nextTick();
|
await this.$nextTick();
|
||||||
setTimeout(() => this.$router.push(url), 0);
|
setTimeout(() => this.$router.push(url), 0);
|
||||||
},
|
},
|
||||||
getContext(url) {
|
|
||||||
url = url.slice(1);
|
|
||||||
let path = "./" + url.substring(url.indexOf("/") + 1);
|
|
||||||
return path.replace(/\/+$/, "") + "/";
|
|
||||||
},
|
|
||||||
basePath(str,isDir) {
|
basePath(str,isDir) {
|
||||||
let parts = str.replace(/(\/$|^\/)/, "").split("/");
|
let parts = str.replace(/(\/$|^\/)/, "").split("/");
|
||||||
if (parts.length <= 2) {
|
if (parts.length <= 1) {
|
||||||
if (isDir) {
|
if (isDir) {
|
||||||
return "/"
|
return "/"
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
console.log("basePath",parts)
|
||||||
parts.pop();
|
parts.pop();
|
||||||
parts = parts.join("/") + "/";
|
parts = parts.join("/") + "/";
|
||||||
if (isDir) {
|
if (isDir) {
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
<languages
|
<languages
|
||||||
class="input input--block"
|
class="input input--block"
|
||||||
id="locale"
|
id="locale"
|
||||||
:locale.sync="user.locale"
|
v-model:locale="user.locale"
|
||||||
></languages>
|
></languages>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -55,13 +55,13 @@
|
||||||
{{ $t("settings.lockPassword") }}
|
{{ $t("settings.lockPassword") }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<permissions :perm.sync="user.perm" />
|
<permissions :perm="user.perm" />
|
||||||
<commands v-if="isExecEnabled" :commands.sync="user.commands" />
|
<commands v-if="isExecEnabled" v-model:commands="user.commands" />
|
||||||
|
|
||||||
<div v-if="!isDefault">
|
<div v-if="!isDefault">
|
||||||
<h3>{{ $t("settings.rules") }}</h3>
|
<h3>{{ $t("settings.rules") }}</h3>
|
||||||
<p class="small">{{ $t("settings.rulesHelp") }}</p>
|
<p class="small">{{ $t("settings.rulesHelp") }}</p>
|
||||||
<rules :rules.sync="user.rules" />
|
<rules v-model:rules="user.rules" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -75,7 +75,7 @@ import { enableExec } from "@/utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "user",
|
name: "user",
|
||||||
data: () => {
|
data() {
|
||||||
return {
|
return {
|
||||||
createUserDirData: false,
|
createUserDirData: false,
|
||||||
originalUserScope: "/",
|
originalUserScope: "/",
|
||||||
|
@ -104,15 +104,17 @@ export default {
|
||||||
displayHomeDirectoryCheckbox() {
|
displayHomeDirectoryCheckbox() {
|
||||||
return this.isNew && this.createUserDir;
|
return this.isNew && this.createUserDir;
|
||||||
},
|
},
|
||||||
isExecEnabled: () => enableExec,
|
isExecEnabled() {
|
||||||
|
return enableExec; // Removed arrow function
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
"user.perm.admin": function () {
|
"user.perm.admin": function () {
|
||||||
if (!this.user.perm.admin) return;
|
if (!this.user.perm.admin) return;
|
||||||
this.user.lockPassword = false;
|
this.user.lockPassword = false;
|
||||||
},
|
},
|
||||||
createUserDirData() {
|
createUserDirData(newVal) {
|
||||||
this.user.scope = this.createUserDirData ? "" : this.originalUserScope;
|
this.user.scope = newVal ? "" : this.originalUserScope;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
<h3>{{ $t("settings.rules") }}</h3>
|
<h3>{{ $t("settings.rules") }}</h3>
|
||||||
<p class="small">{{ $t("settings.globalRules") }}</p>
|
<p class="small">{{ $t("settings.globalRules") }}</p>
|
||||||
<rules :rules.sync="settings.rules" />
|
<rules :rules="settings.rules" @update:rules="updateRules" />
|
||||||
|
|
||||||
<div v-if="isExecEnabled">
|
<div v-if="isExecEnabled">
|
||||||
<h3>{{ $t("settings.executeOnShell") }}</h3>
|
<h3>{{ $t("settings.executeOnShell") }}</h3>
|
||||||
|
@ -116,7 +116,8 @@
|
||||||
<user-form
|
<user-form
|
||||||
:isNew="false"
|
:isNew="false"
|
||||||
:isDefault="true"
|
:isDefault="true"
|
||||||
:user.sync="settings.defaults"
|
:user="settings.defaults"
|
||||||
|
@update:user="updateUser"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -149,8 +150,8 @@
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="command in settings.commands"
|
v-for="(command, index) in settings.commands"
|
||||||
:key="command.name"
|
:key="index"
|
||||||
class="collapsible"
|
class="collapsible"
|
||||||
>
|
>
|
||||||
<input :id="command.name" type="checkbox" />
|
<input :id="command.name" type="checkbox" />
|
||||||
|
@ -231,6 +232,12 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["setLoading"]),
|
...mapMutations(["setLoading"]),
|
||||||
|
updateRules(updatedRules) {
|
||||||
|
this.settings.rules = updatedRules;
|
||||||
|
},
|
||||||
|
updateUser(updatedUser) {
|
||||||
|
this.settings.defaults = updatedUser;
|
||||||
|
},
|
||||||
capitalize(name, where = "_") {
|
capitalize(name, where = "_") {
|
||||||
if (where === "caps") where = /(?=[A-Z])/;
|
if (where === "caps") where = /(?=[A-Z])/;
|
||||||
let splitted = name.split(where);
|
let splitted = name.split(where);
|
||||||
|
|
|
@ -26,13 +26,15 @@
|
||||||
<h3>Listing View Style</h3>
|
<h3>Listing View Style</h3>
|
||||||
<ViewMode
|
<ViewMode
|
||||||
class="input input--block"
|
class="input input--block"
|
||||||
:viewMode.sync="viewMode"
|
:viewMode="viewMode"
|
||||||
|
@update:viewMode="updateViewMode"
|
||||||
></ViewMode>
|
></ViewMode>
|
||||||
<h3>{{ $t("settings.language") }}</h3>
|
<h3>{{ $t("settings.language") }}</h3>
|
||||||
<languages
|
<Languages
|
||||||
class="input input--block"
|
class="input input--block"
|
||||||
:locale.sync="locale"
|
:locale="locale"
|
||||||
></languages>
|
@update:locale="updateLocale"
|
||||||
|
></Languages>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
|
@ -93,7 +95,7 @@ export default {
|
||||||
ViewMode,
|
ViewMode,
|
||||||
Languages,
|
Languages,
|
||||||
},
|
},
|
||||||
data: function () {
|
data() {
|
||||||
return {
|
return {
|
||||||
password: "",
|
password: "",
|
||||||
passwordConf: "",
|
passwordConf: "",
|
||||||
|
@ -184,6 +186,12 @@ export default {
|
||||||
this.$showError(e);
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
updateViewMode(updatedMode) {
|
||||||
|
this.viewMode = updatedMode;
|
||||||
|
},
|
||||||
|
updateLocale(updatedLocale) {
|
||||||
|
this.locale = updatedLocale;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -10,10 +10,12 @@
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<user-form
|
<user-form
|
||||||
:user.sync="user"
|
:user="user"
|
||||||
:createUserDir.sync="createUserDir"
|
:createUserDir="createUserDir"
|
||||||
:isDefault="false"
|
:isDefault="false"
|
||||||
:isNew="isNew"
|
:isNew="isNew"
|
||||||
|
@update:user="updatedUser => user = updatedUser"
|
||||||
|
@update:createUserDir="updatedDir => createUserDir = updatedDir"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@ export default {
|
||||||
UserForm,
|
UserForm,
|
||||||
Errors,
|
Errors,
|
||||||
},
|
},
|
||||||
data: () => {
|
data() {
|
||||||
return {
|
return {
|
||||||
error: null,
|
error: null,
|
||||||
originalUser: null,
|
originalUser: null,
|
||||||
|
@ -91,7 +93,7 @@ export default {
|
||||||
},
|
},
|
||||||
...mapState(["loading"]),
|
...mapState(["loading"]),
|
||||||
showDeletePrompt() {
|
showDeletePrompt() {
|
||||||
return this.showDelete
|
return this.showDelete;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -129,7 +131,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deletePrompt() {
|
deletePrompt() {
|
||||||
this.showDelete = true
|
this.showDelete = true;
|
||||||
},
|
},
|
||||||
async deleteUser(event) {
|
async deleteUser(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
18
roadmap.md
18
roadmap.md
|
@ -1,19 +1,10 @@
|
||||||
# Planned Roadmap
|
# Planned Roadmap
|
||||||
|
|
||||||
Next release (0.2.1):
|
Next version :
|
||||||
|
|
||||||
- Improve browsing directory performance by utilizing the index.
|
|
||||||
- Add editor themes back that were removed because of issues.
|
|
||||||
- Add "running config" which is editable in filebrowser settings to add rules, users, settings which would normally be done via commands.
|
|
||||||
- baseurl issue https://github.com/filebrowser/filebrowser/pull/2579
|
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2526
|
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2698
|
|
||||||
- https://github.com/filebrowser/filebrowser/pull/2667
|
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2632
|
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2619
|
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2618
|
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2607
|
|
||||||
|
|
||||||
|
- Feature: config gets updated when settings change, ensuring that running settings are up to date.
|
||||||
|
- Feature: Move / Create Action Dialogs https://github.com/filebrowser/filebrowser/pull/2667
|
||||||
|
- Feature: playable shared video https://github.com/filebrowser/filebrowser/issues/2537
|
||||||
|
|
||||||
Future releases (within 6 months):
|
Future releases (within 6 months):
|
||||||
|
|
||||||
|
@ -26,4 +17,3 @@ Future releases (within 6 months):
|
||||||
- Use vite instead of webpack
|
- Use vite instead of webpack
|
||||||
- upgrade to vue3
|
- upgrade to vue3
|
||||||
- support minio/s3 https://github.com/filebrowser/filebrowser/issues/2544
|
- support minio/s3 https://github.com/filebrowser/filebrowser/issues/2544
|
||||||
- https://github.com/filebrowser/filebrowser/issues/2537
|
|
||||||
|
|
Loading…
Reference in New Issue