mirror of
https://github.com/filebrowser/filebrowser.git
synced 2025-07-28 19:00:28 +00:00
feat: Allow file and directory creation modes to be configured
The defaults remain the same as before. For now, the config options are global instead of per-user. Note also that the BoltDB creation maintains the old default mode of 0640 since it's not really a user-facing filesystem manipulation. Fixes #5316, #5200
This commit is contained in:
parent
5b7ea9f95a
commit
21ad653b7e
@ -49,6 +49,10 @@ func addConfigFlags(flags *pflag.FlagSet) {
|
|||||||
flags.String("branding.files", "", "path to directory with images and custom styles")
|
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.disableExternal", false, "disable external links such as GitHub links")
|
||||||
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
|
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")
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo
|
//nolint:gocyclo
|
||||||
@ -170,6 +174,8 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
|
|||||||
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
||||||
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
||||||
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
|
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
|
||||||
|
fmt.Fprintf(w, "\tFile Creation Mode:\t%O\n", set.FileMode)
|
||||||
|
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, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
|
||||||
fmt.Fprintf(w, "\tSorting:\n")
|
fmt.Fprintf(w, "\tSorting:\n")
|
||||||
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
|
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
|
||||||
|
@ -43,6 +43,8 @@ override the options.`,
|
|||||||
Theme: mustGetString(flags, "branding.theme"),
|
Theme: mustGetString(flags, "branding.theme"),
|
||||||
Files: mustGetString(flags, "branding.files"),
|
Files: mustGetString(flags, "branding.files"),
|
||||||
},
|
},
|
||||||
|
FileMode: mustGetMode(flags, "file-mode"),
|
||||||
|
DirMode: mustGetMode(flags, "dir-mode"),
|
||||||
}
|
}
|
||||||
|
|
||||||
ser := &settings.Server{
|
ser := &settings.Server{
|
||||||
|
@ -65,6 +65,10 @@ you want to change. Other options will remain unchanged.`,
|
|||||||
set.Branding.DisableUsedPercentage = mustGetBool(flags, flag.Name)
|
set.Branding.DisableUsedPercentage = mustGetBool(flags, flag.Name)
|
||||||
case "branding.files":
|
case "branding.files":
|
||||||
set.Branding.Files = mustGetString(flags, flag.Name)
|
set.Branding.Files = mustGetString(flags, flag.Name)
|
||||||
|
case "file-mode":
|
||||||
|
set.FileMode = mustGetMode(flags, flag.Name)
|
||||||
|
case "dir-mode":
|
||||||
|
set.DirMode = mustGetMode(flags, flag.Name)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
14
cmd/utils.go
14
cmd/utils.go
@ -4,9 +4,11 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/asdine/storm/v3"
|
"github.com/asdine/storm/v3"
|
||||||
@ -14,12 +16,13 @@ import (
|
|||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
yaml "gopkg.in/yaml.v2"
|
yaml "gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/files"
|
|
||||||
"github.com/filebrowser/filebrowser/v2/settings"
|
"github.com/filebrowser/filebrowser/v2/settings"
|
||||||
"github.com/filebrowser/filebrowser/v2/storage"
|
"github.com/filebrowser/filebrowser/v2/storage"
|
||||||
"github.com/filebrowser/filebrowser/v2/storage/bolt"
|
"github.com/filebrowser/filebrowser/v2/storage/bolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const dbPerms = 0640
|
||||||
|
|
||||||
func checkErr(err error) {
|
func checkErr(err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@ -32,6 +35,13 @@ func mustGetString(flags *pflag.FlagSet, flag string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func mustGetMode(flags *pflag.FlagSet, flag string) fs.FileMode {
|
||||||
|
s := mustGetString(flags, flag)
|
||||||
|
b, err := strconv.ParseUint(s, 0, 32)
|
||||||
|
checkErr(err)
|
||||||
|
return fs.FileMode(b)
|
||||||
|
}
|
||||||
|
|
||||||
func mustGetBool(flags *pflag.FlagSet, flag string) bool {
|
func mustGetBool(flags *pflag.FlagSet, flag string) bool {
|
||||||
b, err := flags.GetBool(flag)
|
b, err := flags.GetBool(flag)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
@ -106,7 +116,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
|||||||
|
|
||||||
log.Println("Using database: " + absPath)
|
log.Println("Using database: " + absPath)
|
||||||
data.hadDB = exists
|
data.hadDB = exists
|
||||||
db, err := storm.Open(path, storm.BoltOptions(files.PermFile, nil))
|
db, err := storm.Open(path, storm.BoltOptions(dbPerms, nil))
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
data.store, err = bolt.NewStorage(db)
|
data.store, err = bolt.NewStorage(db)
|
||||||
|
@ -27,9 +27,6 @@ import (
|
|||||||
"github.com/filebrowser/filebrowser/v2/rules"
|
"github.com/filebrowser/filebrowser/v2/rules"
|
||||||
)
|
)
|
||||||
|
|
||||||
const PermFile = 0640
|
|
||||||
const PermDir = 0750
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
reSubDirs = regexp.MustCompile("(?i)^sub(s|titles)$")
|
reSubDirs = regexp.MustCompile("(?i)^sub(s|titles)$")
|
||||||
reSubExts = regexp.MustCompile("(?i)(.vtt|.srt|.ass|.ssa)$")
|
reSubExts = regexp.MustCompile("(?i)(.vtt|.srt|.ass|.ssa)$")
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package fileutils
|
package fileutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
@ -8,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Copy copies a file or folder from one place to another.
|
// Copy copies a file or folder from one place to another.
|
||||||
func Copy(fs afero.Fs, src, dst string) error {
|
func Copy(afs afero.Fs, src, dst string, fileMode, dirMode fs.FileMode) error {
|
||||||
if src = path.Clean("/" + src); src == "" {
|
if src = path.Clean("/" + src); src == "" {
|
||||||
return os.ErrNotExist
|
return os.ErrNotExist
|
||||||
}
|
}
|
||||||
@ -26,14 +27,14 @@ func Copy(fs afero.Fs, src, dst string) error {
|
|||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := fs.Stat(src)
|
info, err := afs.Stat(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
return CopyDir(fs, src, dst)
|
return CopyDir(afs, src, dst, fileMode, dirMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
return CopyFile(fs, src, dst)
|
return CopyFile(afs, src, dst, fileMode, dirMode)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package fileutils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
@ -9,20 +10,20 @@ import (
|
|||||||
// CopyDir copies a directory from source to dest and all
|
// CopyDir copies a directory from source to dest and all
|
||||||
// of its sub-directories. It doesn't stop if it finds an error
|
// of its sub-directories. It doesn't stop if it finds an error
|
||||||
// during the copy. Returns an error if any.
|
// during the copy. Returns an error if any.
|
||||||
func CopyDir(fs afero.Fs, source, dest string) error {
|
func CopyDir(afs afero.Fs, source, dest string, fileMode, dirMode fs.FileMode) error {
|
||||||
// Get properties of source.
|
// Get properties of source.
|
||||||
srcinfo, err := fs.Stat(source)
|
srcinfo, err := afs.Stat(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the destination directory.
|
// Create the destination directory.
|
||||||
err = fs.MkdirAll(dest, srcinfo.Mode())
|
err = afs.MkdirAll(dest, srcinfo.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, _ := fs.Open(source)
|
dir, _ := afs.Open(source)
|
||||||
obs, err := dir.Readdir(-1)
|
obs, err := dir.Readdir(-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -36,13 +37,13 @@ func CopyDir(fs afero.Fs, source, dest string) error {
|
|||||||
|
|
||||||
if obj.IsDir() {
|
if obj.IsDir() {
|
||||||
// Create sub-directories, recursively.
|
// Create sub-directories, recursively.
|
||||||
err = CopyDir(fs, fsource, fdest)
|
err = CopyDir(afs, fsource, fdest, fileMode, dirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Perform the file copy.
|
// Perform the file copy.
|
||||||
err = CopyFile(fs, fsource, fdest)
|
err = CopyFile(afs, fsource, fdest, fileMode, dirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
@ -2,29 +2,28 @@ package fileutils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/files"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// MoveFile moves file from src to dst.
|
// MoveFile moves file from src to dst.
|
||||||
// By default the rename filesystem system call is used. If src and dst point to different volumes
|
// By default the rename filesystem system call is used. If src and dst point to different volumes
|
||||||
// the file copy is used as a fallback
|
// the file copy is used as a fallback
|
||||||
func MoveFile(fs afero.Fs, src, dst string) error {
|
func MoveFile(afs afero.Fs, src, dst string, fileMode, dirMode fs.FileMode) error {
|
||||||
if fs.Rename(src, dst) == nil {
|
if afs.Rename(src, dst) == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// fallback
|
// fallback
|
||||||
err := Copy(fs, src, dst)
|
err := Copy(afs, src, dst, fileMode, dirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = fs.Remove(dst)
|
_ = afs.Remove(dst)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fs.RemoveAll(src); err != nil {
|
if err := afs.RemoveAll(src); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -32,9 +31,9 @@ func MoveFile(fs afero.Fs, src, dst string) error {
|
|||||||
|
|
||||||
// CopyFile copies a file from source to dest and returns
|
// CopyFile copies a file from source to dest and returns
|
||||||
// an error if any.
|
// an error if any.
|
||||||
func CopyFile(fs afero.Fs, source, dest string) error {
|
func CopyFile(afs afero.Fs, source, dest string, fileMode, dirMode fs.FileMode) error {
|
||||||
// Open the source file.
|
// Open the source file.
|
||||||
src, err := fs.Open(source)
|
src, err := afs.Open(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -42,13 +41,13 @@ func CopyFile(fs afero.Fs, source, dest string) error {
|
|||||||
|
|
||||||
// Makes the directory needed to create the dst
|
// Makes the directory needed to create the dst
|
||||||
// file.
|
// file.
|
||||||
err = fs.MkdirAll(filepath.Dir(dest), files.PermDir)
|
err = afs.MkdirAll(filepath.Dir(dest), dirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the destination file.
|
// Create the destination file.
|
||||||
dst, err := fs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, files.PermFile)
|
dst, err := afs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -61,11 +60,11 @@ func CopyFile(fs afero.Fs, source, dest string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy the mode
|
// Copy the mode
|
||||||
info, err := fs.Stat(source)
|
info, err := afs.Stat(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = fs.Chmod(dest, info.Mode())
|
err = afs.Chmod(dest, info.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -105,7 +106,7 @@ func resourcePostHandler(fileCache FileCache) handleFunc {
|
|||||||
|
|
||||||
// Directories creation on POST.
|
// Directories creation on POST.
|
||||||
if strings.HasSuffix(r.URL.Path, "/") {
|
if strings.HasSuffix(r.URL.Path, "/") {
|
||||||
err := d.user.Fs.MkdirAll(r.URL.Path, files.PermDir)
|
err := d.user.Fs.MkdirAll(r.URL.Path, d.settings.DirMode)
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +135,7 @@ func resourcePostHandler(fileCache FileCache) handleFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = d.RunHook(func() error {
|
err = d.RunHook(func() error {
|
||||||
info, writeErr := writeFile(d.user.Fs, r.URL.Path, r.Body)
|
info, writeErr := writeFile(d.user.Fs, r.URL.Path, r.Body, d.settings.FileMode, d.settings.DirMode)
|
||||||
if writeErr != nil {
|
if writeErr != nil {
|
||||||
return writeErr
|
return writeErr
|
||||||
}
|
}
|
||||||
@ -171,7 +172,7 @@ var resourcePutHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = d.RunHook(func() error {
|
err = d.RunHook(func() error {
|
||||||
info, writeErr := writeFile(d.user.Fs, r.URL.Path, r.Body)
|
info, writeErr := writeFile(d.user.Fs, r.URL.Path, r.Body, d.settings.FileMode, d.settings.DirMode)
|
||||||
if writeErr != nil {
|
if writeErr != nil {
|
||||||
return writeErr
|
return writeErr
|
||||||
}
|
}
|
||||||
@ -243,14 +244,14 @@ func checkParent(src, dst string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addVersionSuffix(source string, fs afero.Fs) string {
|
func addVersionSuffix(source string, afs afero.Fs) string {
|
||||||
counter := 1
|
counter := 1
|
||||||
dir, name := path.Split(source)
|
dir, name := path.Split(source)
|
||||||
ext := filepath.Ext(name)
|
ext := filepath.Ext(name)
|
||||||
base := strings.TrimSuffix(name, ext)
|
base := strings.TrimSuffix(name, ext)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if _, err := fs.Stat(source); err != nil {
|
if _, err := afs.Stat(source); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
renamed := fmt.Sprintf("%s(%d)%s", base, counter, ext)
|
renamed := fmt.Sprintf("%s(%d)%s", base, counter, ext)
|
||||||
@ -261,14 +262,14 @@ func addVersionSuffix(source string, fs afero.Fs) string {
|
|||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFile(fs afero.Fs, dst string, in io.Reader) (os.FileInfo, error) {
|
func writeFile(afs afero.Fs, dst string, in io.Reader, fileMode, dirMode fs.FileMode) (os.FileInfo, error) {
|
||||||
dir, _ := path.Split(dst)
|
dir, _ := path.Split(dst)
|
||||||
err := fs.MkdirAll(dir, files.PermDir)
|
err := afs.MkdirAll(dir, dirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := fs.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, files.PermFile)
|
file, err := afs.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fileMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -306,7 +307,7 @@ func patchAction(ctx context.Context, action, src, dst string, d *data, fileCach
|
|||||||
return fbErrors.ErrPermissionDenied
|
return fbErrors.ErrPermissionDenied
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileutils.Copy(d.user.Fs, src, dst)
|
return fileutils.Copy(d.user.Fs, src, dst, d.settings.FileMode, d.settings.DirMode)
|
||||||
case "rename":
|
case "rename":
|
||||||
if !d.user.Perm.Rename {
|
if !d.user.Perm.Rename {
|
||||||
return fbErrors.ErrPermissionDenied
|
return fbErrors.ErrPermissionDenied
|
||||||
@ -332,7 +333,7 @@ func patchAction(ctx context.Context, action, src, dst string, d *data, fileCach
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileutils.MoveFile(d.user.Fs, src, dst)
|
return fileutils.MoveFile(d.user.Fs, src, dst, d.settings.FileMode, d.settings.DirMode)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported action %s: %w", action, fbErrors.ErrInvalidRequestParams)
|
return fmt.Errorf("unsupported action %s: %w", action, fbErrors.ErrInvalidRequestParams)
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ func tusPostHandler() handleFunc {
|
|||||||
case errors.Is(err, afero.ErrFileNotFound):
|
case errors.Is(err, afero.ErrFileNotFound):
|
||||||
dirPath := filepath.Dir(r.URL.Path)
|
dirPath := filepath.Dir(r.URL.Path)
|
||||||
if _, statErr := d.user.Fs.Stat(dirPath); os.IsNotExist(statErr) {
|
if _, statErr := d.user.Fs.Stat(dirPath); os.IsNotExist(statErr) {
|
||||||
if mkdirErr := d.user.Fs.MkdirAll(dirPath, files.PermDir); mkdirErr != nil {
|
if mkdirErr := d.user.Fs.MkdirAll(dirPath, d.settings.DirMode); mkdirErr != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ func tusPostHandler() handleFunc {
|
|||||||
fileFlags |= os.O_TRUNC
|
fileFlags |= os.O_TRUNC
|
||||||
}
|
}
|
||||||
|
|
||||||
openFile, err := d.user.Fs.OpenFile(r.URL.Path, fileFlags, files.PermFile)
|
openFile, err := d.user.Fs.OpenFile(r.URL.Path, fileFlags, d.settings.FileMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
@ -239,7 +239,7 @@ func tusPatchHandler() handleFunc {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
openFile, err := d.user.Fs.OpenFile(r.URL.Path, os.O_WRONLY|os.O_APPEND, files.PermFile)
|
openFile, err := d.user.Fs.OpenFile(r.URL.Path, os.O_WRONLY|os.O_APPEND, d.settings.FileMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, fmt.Errorf("could not open file: %w", err)
|
return http.StatusInternalServerError, fmt.Errorf("could not open file: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package settings
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -11,6 +12,8 @@ import (
|
|||||||
|
|
||||||
const DefaultUsersHomeBasePath = "/users"
|
const DefaultUsersHomeBasePath = "/users"
|
||||||
const DefaultMinimumPasswordLength = 12
|
const DefaultMinimumPasswordLength = 12
|
||||||
|
const DefaultFileMode = 0640
|
||||||
|
const DefaultDirMode = 0750
|
||||||
|
|
||||||
// AuthMethod describes an authentication method.
|
// AuthMethod describes an authentication method.
|
||||||
type AuthMethod string
|
type AuthMethod string
|
||||||
@ -29,6 +32,8 @@ type Settings struct {
|
|||||||
Shell []string `json:"shell"`
|
Shell []string `json:"shell"`
|
||||||
Rules []rules.Rule `json:"rules"`
|
Rules []rules.Rule `json:"rules"`
|
||||||
MinimumPasswordLength uint `json:"minimumPasswordLength"`
|
MinimumPasswordLength uint `json:"minimumPasswordLength"`
|
||||||
|
FileMode fs.FileMode `json:"fileMode"`
|
||||||
|
DirMode fs.FileMode `json:"dirMode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRules implements rules.Provider.
|
// GetRules implements rules.Provider.
|
||||||
|
@ -42,6 +42,12 @@ func (s *Storage) Get() (*Settings, error) {
|
|||||||
RetryCount: DefaultTusRetryCount,
|
RetryCount: DefaultTusRetryCount,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if set.FileMode == 0 {
|
||||||
|
set.FileMode = DefaultFileMode
|
||||||
|
}
|
||||||
|
if set.DirMode == 0 {
|
||||||
|
set.DirMode = DefaultDirMode
|
||||||
|
}
|
||||||
return set, nil
|
return set, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user