Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0bc9167b1 | ||
|
|
23d646c456 | ||
|
|
76add9e527 | ||
|
|
c63cc5a2d2 | ||
|
|
25c8788390 | ||
|
|
aa52b07bb1 | ||
|
|
76b466f649 | ||
|
|
8ecc2da947 | ||
|
|
8650d2ffe7 | ||
|
|
34d7d2c8c4 | ||
|
|
201329abce | ||
|
|
f2b5dd3787 | ||
|
|
5072bbb2cb | ||
|
|
6b19ab6613 | ||
|
|
730be5ef6b | ||
|
|
46ee595389 | ||
|
|
dee465ab86 | ||
|
|
209f9fa77f | ||
|
|
ba8c09f454 | ||
|
|
16a34defc0 | ||
|
|
7d1e03075d | ||
|
|
1c25f6ee69 | ||
|
|
aa172b8bb5 | ||
|
|
4711e7bcd5 | ||
|
|
8a47aee137 | ||
|
|
190cb99a79 | ||
|
|
603203848a | ||
|
|
5e6f14b5dc | ||
|
|
976eb5583d | ||
|
|
b92152693f | ||
|
|
7ec24d9d77 | ||
|
|
20ebbf6611 | ||
|
|
ba7e71a7c3 | ||
|
|
8973c4598f | ||
|
|
18889ad725 |
@@ -6,6 +6,8 @@ linters-settings:
|
|||||||
funlen:
|
funlen:
|
||||||
lines: 100
|
lines: 100
|
||||||
statements: 50
|
statements: 50
|
||||||
|
gci:
|
||||||
|
local-prefixes: github.com/filebrowser/filebrowser
|
||||||
goconst:
|
goconst:
|
||||||
min-len: 2
|
min-len: 2
|
||||||
min-occurrences: 2
|
min-occurrences: 2
|
||||||
@@ -26,8 +28,6 @@ linters-settings:
|
|||||||
min-complexity: 15
|
min-complexity: 15
|
||||||
goimports:
|
goimports:
|
||||||
local-prefixes: github.com/filebrowser/filebrowser
|
local-prefixes: github.com/filebrowser/filebrowser
|
||||||
golint:
|
|
||||||
min-confidence: 0
|
|
||||||
gomnd:
|
gomnd:
|
||||||
settings:
|
settings:
|
||||||
mnd:
|
mnd:
|
||||||
@@ -58,26 +58,25 @@ linters:
|
|||||||
- dogsled
|
- dogsled
|
||||||
- dupl
|
- dupl
|
||||||
- errcheck
|
- errcheck
|
||||||
|
- exportloopref
|
||||||
|
- exhaustive
|
||||||
- funlen
|
- funlen
|
||||||
- gochecknoinits
|
- gochecknoinits
|
||||||
- goconst
|
- goconst
|
||||||
- gocritic
|
- gocritic
|
||||||
- gocyclo
|
- gocyclo
|
||||||
- goimports
|
- goimports
|
||||||
- golint
|
|
||||||
- gomnd
|
- gomnd
|
||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
- gosec
|
- gosec
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- interfacer
|
|
||||||
- lll
|
- lll
|
||||||
- misspell
|
- misspell
|
||||||
- nakedret
|
- nakedret
|
||||||
- nolintlint
|
- nolintlint
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- scopelint
|
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- structcheck
|
- structcheck
|
||||||
- stylecheck
|
- stylecheck
|
||||||
@@ -89,19 +88,6 @@ linters:
|
|||||||
- whitespace
|
- whitespace
|
||||||
- prealloc
|
- prealloc
|
||||||
|
|
||||||
# don't enable:
|
|
||||||
# - asciicheck
|
|
||||||
# - exhaustive (TODO: enable after next release; current release at time of writing is v1.27)
|
|
||||||
# - gochecknoglobals
|
|
||||||
# - gocognit
|
|
||||||
# - godot
|
|
||||||
# - godox
|
|
||||||
# - goerr113
|
|
||||||
# - maligned
|
|
||||||
# - nestif
|
|
||||||
# - testpackage
|
|
||||||
# - wsl
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
exclude-rules:
|
exclude-rules:
|
||||||
- path: cmd/.*.go
|
- path: cmd/.*.go
|
||||||
@@ -118,6 +104,9 @@ issues:
|
|||||||
- text: "Auther"
|
- text: "Auther"
|
||||||
linters:
|
linters:
|
||||||
- misspell
|
- misspell
|
||||||
|
- text: "strconv.Parse"
|
||||||
|
linters:
|
||||||
|
- gomnd
|
||||||
|
|
||||||
run:
|
run:
|
||||||
skip-dirs:
|
skip-dirs:
|
||||||
|
|||||||
50
CHANGELOG.md
50
CHANGELOG.md
@@ -2,6 +2,56 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
## [2.17.0](https://github.com/filebrowser/filebrowser/compare/v2.16.1...v2.17.0) (2021-08-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* open file option on preview ([76add9e](https://github.com/filebrowser/filebrowser/commit/76add9e5274b0373c6b983e3b20e387a14ea6c9e))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* 401 error in share view open file button ([#1495](https://github.com/filebrowser/filebrowser/issues/1495)) ([25c8788](https://github.com/filebrowser/filebrowser/commit/25c87883908babde073390a2e2320a8e5880a87c))
|
||||||
|
* escape quote on index template ([23d646c](https://github.com/filebrowser/filebrowser/commit/23d646c456876d06cf48e71c1e57b69de99511f0)), closes [#1501](https://github.com/filebrowser/filebrowser/issues/1501)
|
||||||
|
* file caching directive ([c63cc5a](https://github.com/filebrowser/filebrowser/commit/c63cc5a2d25909cc4e2f2e7235f276ec66c32bf2))
|
||||||
|
|
||||||
|
### [2.16.1](https://github.com/filebrowser/filebrowser/compare/v2.16.0...v2.16.1) (2021-08-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* check symlink target type (closes [#1488](https://github.com/filebrowser/filebrowser/issues/1488)) ([76b466f](https://github.com/filebrowser/filebrowser/commit/76b466f6492e74cf13e66a33e7e5f597ac92b240))
|
||||||
|
|
||||||
|
## [2.16.0](https://github.com/filebrowser/filebrowser/compare/v2.15.0...v2.16.0) (2021-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* browser cache directives ([190cb99](https://github.com/filebrowser/filebrowser/commit/190cb99a79a0d438eca2da13539f8c6449ad73ac))
|
||||||
|
* display error messages on settings ([6032038](https://github.com/filebrowser/filebrowser/commit/603203848a8b2221158088b6d849609db4c0c46c))
|
||||||
|
* file name on page title ([16a34de](https://github.com/filebrowser/filebrowser/commit/16a34defc02554a77c6ac47b9e17e69d098a09fe))
|
||||||
|
* gzip encoding for static js files ([aa172b8](https://github.com/filebrowser/filebrowser/commit/aa172b8bb5f17d5f5cb9666bfb5ee650d8091fb5))
|
||||||
|
* loading spinner on views navigation ([976eb55](https://github.com/filebrowser/filebrowser/commit/976eb5583dae474125fd7ddec5dc19b6c291f98f))
|
||||||
|
* message for connection error ([5e6f14b](https://github.com/filebrowser/filebrowser/commit/5e6f14b5dcb9c5efdf526f1346e09c2d0b2f6974))
|
||||||
|
* mod time title on file info ([7d1e030](https://github.com/filebrowser/filebrowser/commit/7d1e03075d2c27148f60813defa0f68403d1d3c2))
|
||||||
|
* open file option on share ([1c25f6e](https://github.com/filebrowser/filebrowser/commit/1c25f6ee69bd71eed82af7020006d0e27537a967))
|
||||||
|
* show more button on share ([ba8c09f](https://github.com/filebrowser/filebrowser/commit/ba8c09f454feeadf4a1e97547a34151a81b389d5))
|
||||||
|
* support for IE11 browser ([7ec24d9](https://github.com/filebrowser/filebrowser/commit/7ec24d9d7794fa37825f64ca2d1575f568fb1362))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* break resource create/update handlers on error (closes [#1464](https://github.com/filebrowser/filebrowser/issues/1464)) ([5072bbb](https://github.com/filebrowser/filebrowser/commit/5072bbb2cbf5b29d041629faa8367f15e4d145a2))
|
||||||
|
* copying files with special characters ([20ebbf6](https://github.com/filebrowser/filebrowser/commit/20ebbf6611b734371426fb1b9cb5e388be90bf7e))
|
||||||
|
* delete image cache when moving ([8973c45](https://github.com/filebrowser/filebrowser/commit/8973c4598ff817647f1f1ad6ee36480054cd2776))
|
||||||
|
* don't remove files on unsuccessful updates (closes [#1456](https://github.com/filebrowser/filebrowser/issues/1456)) ([6b19ab6](https://github.com/filebrowser/filebrowser/commit/6b19ab6613b12be7f075299cd98f4b41d43827c7))
|
||||||
|
* failure on broken symlink deletion ([8650d2f](https://github.com/filebrowser/filebrowser/commit/8650d2ffe7a29cbafa800efcecbf6a61598a9f0c))
|
||||||
|
* inconsistent double click on listing item ([ba7e71a](https://github.com/filebrowser/filebrowser/commit/ba7e71a7c3b0cc71012e5adf94b1c642e554972e))
|
||||||
|
* no items displayed on file listing ([18889ad](https://github.com/filebrowser/filebrowser/commit/18889ad725f7f7e5a7e3f7abcf156487556dbeaf))
|
||||||
|
* omit file content ([209f9fa](https://github.com/filebrowser/filebrowser/commit/209f9fa77f751054512355f2b74b9b7258465d0b))
|
||||||
|
* short commit sha and typo fix in Makefile ([#1411](https://github.com/filebrowser/filebrowser/issues/1411)) ([46ee595](https://github.com/filebrowser/filebrowser/commit/46ee59538914dc2859f0da6b32e2d062d0a01b10))
|
||||||
|
|
||||||
## [2.15.0](https://github.com/filebrowser/filebrowser/compare/v2.14.1...v2.15.0) (2021-04-06)
|
## [2.15.0](https://github.com/filebrowser/filebrowser/compare/v2.14.1...v2.15.0) (2021-04-06)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
8
Makefile
8
Makefile
@@ -20,10 +20,10 @@ MODULE = $(shell env GO111MODULE=on $(GO) list -m)
|
|||||||
DATE ?= $(shell date +%FT%T%z)
|
DATE ?= $(shell date +%FT%T%z)
|
||||||
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
|
VERSION ?= $(shell git describe --tags --always --match=v* 2> /dev/null || \
|
||||||
cat $(CURDIR)/.version 2> /dev/null || echo v0)
|
cat $(CURDIR)/.version 2> /dev/null || echo v0)
|
||||||
VERSION_HASH = $(shell git rev-parse HEAD)
|
VERSION_HASH = $(shell git rev-parse --short HEAD)
|
||||||
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
|
|
||||||
LDFLAGS += -X "$(MODULE)/varsion.Version=$(VERSION)" -X "$(MODULE)/varsion.CommitSHA=$(VERSION_HASH)"
|
LDFLAGS += -X "$(MODULE)/version.Version=$(VERSION)" -X "$(MODULE)/version.CommitSHA=$(VERSION_HASH)"
|
||||||
|
|
||||||
# tools
|
# tools
|
||||||
$(BIN):
|
$(BIN):
|
||||||
@@ -32,10 +32,10 @@ $(BIN)/%: | $(BIN) ; $(info $(M) installing $(PACKAGE)…)
|
|||||||
$Q env GOBIN=$(BIN) $(GO) install $(PACKAGE)
|
$Q env GOBIN=$(BIN) $(GO) install $(PACKAGE)
|
||||||
|
|
||||||
GOLANGCI_LINT = $(BIN)/golangci-lint
|
GOLANGCI_LINT = $(BIN)/golangci-lint
|
||||||
$(BIN)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint@v1.37.1
|
$(BIN)/golangci-lint: PACKAGE=github.com/golangci/golangci-lint/cmd/golangci-lint@v1.41.1
|
||||||
|
|
||||||
GOIMPORTS = $(BIN)/goimports
|
GOIMPORTS = $(BIN)/goimports
|
||||||
$(BIN)/goimports: PACKAGE=golang.org/x/tools/cmd/goimports@v0.1.0
|
$(BIN)/goimports: PACKAGE=golang.org/x/tools/cmd/goimports@v0.1.5
|
||||||
|
|
||||||
## build: Build
|
## build: Build
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
|
|||||||
26
SECURITY.md
Normal file
26
SECURITY.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Use this section to tell people about which versions of your project are
|
||||||
|
currently being supported with security updates.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| 2.x | :white_check_mark: |
|
||||||
|
| < 2.0 | :x: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Vulnerabilities should be reported to filebrowser@googlegroups.com - which is a private, maintainer-only group. Maintainers will attempt to respond to/confirm reports within 2-3 days, but if you believe your report to be "critical" to user safety and security, please note as such in the subject. We have tens of thousands of users using our software, and take security vulnerabilities seriously.
|
||||||
|
|
||||||
|
When reporting an issue, where possible, please provide at least:
|
||||||
|
|
||||||
|
* The commit version the issue was identified at
|
||||||
|
* A proof of concept (plaintext; no binaries)
|
||||||
|
* Steps to reproduce
|
||||||
|
* Your recommended remediation(s), if any.
|
||||||
|
|
||||||
|
The FileBrowser team is a volunteer-only effort, and may reach back out for clarification.
|
||||||
|
|
||||||
|
> Note: Please do not open public issues for security issues, as GitHub does not provide facility for private issues, and deleting the issue makes it hard to triage/respond back to the reporter.
|
||||||
@@ -121,7 +121,7 @@ func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (settings.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
|
func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) //nolint:gomnd
|
||||||
|
|
||||||
fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
|
fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
|
||||||
fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
|
fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ func addServerFlags(flags *pflag.FlagSet) {
|
|||||||
flags.StringP("key", "k", "", "tls key")
|
flags.StringP("key", "k", "", "tls key")
|
||||||
flags.StringP("root", "r", ".", "root to prepend to relative paths")
|
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.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.Uint32("socket-perm", 0666, "unix socket file permissions") //nolint:gomnd
|
||||||
flags.StringP("baseurl", "b", "", "base url")
|
flags.StringP("baseurl", "b", "", "base url")
|
||||||
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
|
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
|
||||||
flags.Int("img-processors", 4, "image processors count")
|
flags.Int("img-processors", 4, "image processors count") //nolint:gomnd
|
||||||
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
|
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
|
||||||
flags.Bool("disable-preview-resize", false, "disable resize of image previews")
|
flags.Bool("disable-preview-resize", false, "disable resize of image previews")
|
||||||
flags.Bool("disable-exec", false, "disables Command Runner feature")
|
flags.Bool("disable-exec", false, "disables Command Runner feature")
|
||||||
@@ -128,7 +128,7 @@ user created with the credentials from options "username" and "password".`,
|
|||||||
cacheDir, err := cmd.Flags().GetString("cache-dir")
|
cacheDir, err := cmd.Flags().GetString("cache-dir")
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
if cacheDir != "" {
|
if cacheDir != "" {
|
||||||
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet
|
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet,gomnd
|
||||||
log.Fatalf("can't make directory %s: %s", cacheDir, err)
|
log.Fatalf("can't make directory %s: %s", cacheDir, err)
|
||||||
}
|
}
|
||||||
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ You can also specify an optional parameter (index_end) so
|
|||||||
you can remove all commands from 'index' to 'index_end',
|
you can remove all commands from 'index' to 'index_end',
|
||||||
including 'index_end'.`,
|
including 'index_end'.`,
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil {
|
if err := cobra.RangeArgs(1, 2)(cmd, args); err != nil { //nolint:gomnd
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ var usersCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printUsers(usrs []*users.User) {
|
func printUsers(usrs []*users.User) {
|
||||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) //nolint:gomnd
|
||||||
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
fmt.Fprintln(w, "ID\tUsername\tScope\tLocale\tV. Mode\tS.Click\tAdmin\tExecute\tCreate\tRename\tModify\tDelete\tShare\tDownload\tPwd Lock")
|
||||||
|
|
||||||
for _, u := range usrs {
|
for _, u := range usrs {
|
||||||
@@ -53,7 +53,7 @@ func printUsers(usrs []*users.User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parseUsernameOrID(arg string) (username string, id uint) {
|
func parseUsernameOrID(arg string) (username string, id uint) {
|
||||||
id64, err := strconv.ParseUint(arg, 10, 0)
|
id64, err := strconv.ParseUint(arg, 10, 64) //nolint:gomnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return arg, 0
|
return arg, 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ func dbExists(path string) (bool, error) {
|
|||||||
d := filepath.Dir(path)
|
d := filepath.Dir(path)
|
||||||
_, err = os.Stat(d)
|
_, err = os.Stat(d)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet
|
if err := os.MkdirAll(d, 0700); err != nil { //nolint:govet,gomnd
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ func (f *FileCache) Store(ctx context.Context, key string, value []byte) error {
|
|||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
fileName := f.getFileName(key)
|
fileName := f.getFileName(key)
|
||||||
if err := f.fs.MkdirAll(filepath.Dir(fileName), 0700); err != nil {
|
if err := f.fs.MkdirAll(filepath.Dir(fileName), 0700); err != nil { //nolint:gomnd
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := afero.WriteFile(f.fs, fileName, value, 0700); err != nil {
|
if err := afero.WriteFile(f.fs, fileName, value, 0700); err != nil { //nolint:gomnd
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type FileInfo struct {
|
|||||||
ModTime time.Time `json:"modified"`
|
ModTime time.Time `json:"modified"`
|
||||||
Mode os.FileMode `json:"mode"`
|
Mode os.FileMode `json:"mode"`
|
||||||
IsDir bool `json:"isDir"`
|
IsDir bool `json:"isDir"`
|
||||||
|
IsSymlink bool `json:"isSymlink"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Subtitles []string `json:"subtitles,omitempty"`
|
Subtitles []string `json:"subtitles,omitempty"`
|
||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
@@ -50,6 +51,7 @@ type FileOptions struct {
|
|||||||
ReadHeader bool
|
ReadHeader bool
|
||||||
Token string
|
Token string
|
||||||
Checker rules.Checker
|
Checker rules.Checker
|
||||||
|
Content bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileInfo creates a File object from a path and a given user. This File
|
// NewFileInfo creates a File object from a path and a given user. This File
|
||||||
@@ -60,12 +62,73 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
|
|||||||
return nil, os.ErrPermission
|
return nil, os.ErrPermission
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := opts.Fs.Stat(opts.Path)
|
file, err := stat(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
file := &FileInfo{
|
if opts.Expand {
|
||||||
|
if file.IsDir {
|
||||||
|
if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { //nolint:govet
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = file.detectType(opts.Modify, opts.Content, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func stat(opts FileOptions) (*FileInfo, error) {
|
||||||
|
var file *FileInfo
|
||||||
|
|
||||||
|
if lstaterFs, ok := opts.Fs.(afero.Lstater); ok {
|
||||||
|
info, _, err := lstaterFs.LstatIfPossible(opts.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
file = &FileInfo{
|
||||||
|
Fs: opts.Fs,
|
||||||
|
Path: opts.Path,
|
||||||
|
Name: info.Name(),
|
||||||
|
ModTime: info.ModTime(),
|
||||||
|
Mode: info.Mode(),
|
||||||
|
IsDir: info.IsDir(),
|
||||||
|
IsSymlink: IsSymlink(info.Mode()),
|
||||||
|
Size: info.Size(),
|
||||||
|
Extension: filepath.Ext(info.Name()),
|
||||||
|
Token: opts.Token,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// regular file
|
||||||
|
if file != nil && !file.IsSymlink {
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fs doesn't support afero.Lstater interface or the file is a symlink
|
||||||
|
info, err := opts.Fs.Stat(opts.Path)
|
||||||
|
if err != nil {
|
||||||
|
// can't follow symlink
|
||||||
|
if file != nil && file.IsSymlink {
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// set correct file size in case of symlink
|
||||||
|
if file != nil && file.IsSymlink {
|
||||||
|
file.Size = info.Size()
|
||||||
|
file.IsDir = info.IsDir()
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
file = &FileInfo{
|
||||||
Fs: opts.Fs,
|
Fs: opts.Fs,
|
||||||
Path: opts.Path,
|
Path: opts.Path,
|
||||||
Name: info.Name(),
|
Name: info.Name(),
|
||||||
@@ -77,21 +140,7 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
|
|||||||
Token: opts.Token,
|
Token: opts.Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Expand {
|
return file, nil
|
||||||
if file.IsDir {
|
|
||||||
if err := file.readListing(opts.Checker, opts.ReadHeader); err != nil { //nolint:govet
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return file, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = file.detectType(opts.Modify, true, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return file, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checksum checksums a given File for a given User, using a specific
|
// Checksum checksums a given File for a given User, using a specific
|
||||||
@@ -203,7 +252,7 @@ func (i *FileInfo) readFirstBytes() []byte {
|
|||||||
}
|
}
|
||||||
defer reader.Close()
|
defer reader.Close()
|
||||||
|
|
||||||
buffer := make([]byte, 512)
|
buffer := make([]byte, 512) //nolint:gomnd
|
||||||
n, err := reader.Read(buffer)
|
n, err := reader.Read(buffer)
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
@@ -251,7 +300,9 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isSymlink := false
|
||||||
if IsSymlink(f.Mode()) {
|
if IsSymlink(f.Mode()) {
|
||||||
|
isSymlink = true
|
||||||
// It's a symbolic link. We try to follow it. If it doesn't work,
|
// It's a symbolic link. We try to follow it. If it doesn't work,
|
||||||
// we stay with the link information instead of the target's.
|
// we stay with the link information instead of the target's.
|
||||||
info, err := i.Fs.Stat(fPath)
|
info, err := i.Fs.Stat(fPath)
|
||||||
@@ -267,6 +318,7 @@ func (i *FileInfo) readListing(checker rules.Checker, readHeader bool) error {
|
|||||||
ModTime: f.ModTime(),
|
ModTime: f.ModTime(),
|
||||||
Mode: f.Mode(),
|
Mode: f.Mode(),
|
||||||
IsDir: f.IsDir(),
|
IsDir: f.IsDir(),
|
||||||
|
IsSymlink: isSymlink,
|
||||||
Extension: filepath.Ext(name),
|
Extension: filepath.Ext(name),
|
||||||
Path: fPath,
|
Path: fPath,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,13 +40,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), 0666)
|
err = fs.MkdirAll(filepath.Dir(dest), 0666) //nolint:gomnd
|
||||||
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, 0775)
|
dst, err := fs.OpenFile(dest, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775) //nolint:gomnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
480
frontend/package-lock.json
generated
480
frontend/package-lock.json
generated
@@ -11,6 +11,7 @@
|
|||||||
"ace-builds": "^1.4.7",
|
"ace-builds": "^1.4.7",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"core-js": "^3.9.1",
|
"core-js": "^3.9.1",
|
||||||
|
"css-vars-ponyfill": "^2.4.3",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
@@ -25,7 +26,8 @@
|
|||||||
"vue-lazyload": "^1.3.3",
|
"vue-lazyload": "^1.3.3",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
"vuex": "^3.1.2",
|
"vuex": "^3.1.2",
|
||||||
"vuex-router-sync": "^5.0.0"
|
"vuex-router-sync": "^5.0.0",
|
||||||
|
"whatwg-fetch": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.1.2",
|
"@vue/cli-plugin-babel": "^4.1.2",
|
||||||
@@ -33,6 +35,7 @@
|
|||||||
"@vue/cli-service": "^4.1.2",
|
"@vue/cli-service": "^4.1.2",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
|
"compression-webpack-plugin": "^6.0.3",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
@@ -1383,6 +1386,46 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@npmcli/move-file": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/move-file/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@npmcli/move-file/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@soda/friendly-errors-webpack-plugin": {
|
"node_modules/@soda/friendly-errors-webpack-plugin": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
||||||
@@ -4092,6 +4135,165 @@
|
|||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/compression-webpack-plugin": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-xzSWiZWwBs+HHGhlYxw0oFaYL/0VYErEqDHCAJhJ3Mza5fmF5JJ4iaB6Ap2JT68C0UhhmoI4Mh37LVz/THv2Fw==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"cacache": "^15.0.5",
|
||||||
|
"find-cache-dir": "^3.3.1",
|
||||||
|
"schema-utils": "^3.0.0",
|
||||||
|
"serialize-javascript": "^5.0.1",
|
||||||
|
"webpack-sources": "^1.4.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"webpack": "^4.0.0 || ^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/cacache": {
|
||||||
|
"version": "15.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz",
|
||||||
|
"integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@npmcli/move-file": "^1.0.1",
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"glob": "^7.1.4",
|
||||||
|
"infer-owner": "^1.0.4",
|
||||||
|
"lru-cache": "^6.0.0",
|
||||||
|
"minipass": "^3.1.1",
|
||||||
|
"minipass-collect": "^1.0.2",
|
||||||
|
"minipass-flush": "^1.0.5",
|
||||||
|
"minipass-pipeline": "^1.2.2",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"p-map": "^4.0.0",
|
||||||
|
"promise-inflight": "^1.0.1",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"ssri": "^8.0.1",
|
||||||
|
"tar": "^6.0.2",
|
||||||
|
"unique-filename": "^1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/p-map": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"aggregate-error": "^3.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/schema-utils": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-schema": "^7.0.6",
|
||||||
|
"ajv": "^6.12.5",
|
||||||
|
"ajv-keywords": "^3.5.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/serialize-javascript": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"randombytes": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/ssri": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/compression-webpack-plugin/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/compression/node_modules/bytes": {
|
"node_modules/compression/node_modules/bytes": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||||
@@ -4663,6 +4865,11 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-vars-ponyfill": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-vars-ponyfill/-/css-vars-ponyfill-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-PBfIwjSu27s8kebu8taEYFM8ehVr8o2Qw4H4nSlJzHAJgcduAqxz4oPmYTJuzgauOKaWII9SHWStQ965fxsdZA=="
|
||||||
|
},
|
||||||
"node_modules/css-what": {
|
"node_modules/css-what": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||||
@@ -9045,6 +9252,25 @@
|
|||||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/minizlib": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/minizlib/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/mississippi": {
|
"node_modules/mississippi": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||||
@@ -12746,6 +12972,50 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tar": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"minizlib": "^2.1.1",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"mkdirp": "bin/cmd.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tar/node_modules/yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/terser": {
|
"node_modules/terser": {
|
||||||
"version": "4.8.0",
|
"version": "4.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||||
@@ -14709,6 +14979,11 @@
|
|||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/whatwg-fetch": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA=="
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||||
@@ -16234,6 +16509,33 @@
|
|||||||
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
|
"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@npmcli/move-file": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"mkdirp": "^1.0.4",
|
||||||
|
"rimraf": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@soda/friendly-errors-webpack-plugin": {
|
"@soda/friendly-errors-webpack-plugin": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.0.tgz",
|
||||||
@@ -18503,6 +18805,120 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"compression-webpack-plugin": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-xzSWiZWwBs+HHGhlYxw0oFaYL/0VYErEqDHCAJhJ3Mza5fmF5JJ4iaB6Ap2JT68C0UhhmoI4Mh37LVz/THv2Fw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"cacache": "^15.0.5",
|
||||||
|
"find-cache-dir": "^3.3.1",
|
||||||
|
"schema-utils": "^3.0.0",
|
||||||
|
"serialize-javascript": "^5.0.1",
|
||||||
|
"webpack-sources": "^1.4.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cacache": {
|
||||||
|
"version": "15.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.6.tgz",
|
||||||
|
"integrity": "sha512-g1WYDMct/jzW+JdWEyjaX2zoBkZ6ZT9VpOyp2I/VMtDsNLffNat3kqPFfi1eDRSK9/SuKGyORDHcQMcPF8sQ/w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@npmcli/move-file": "^1.0.1",
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"glob": "^7.1.4",
|
||||||
|
"infer-owner": "^1.0.4",
|
||||||
|
"lru-cache": "^6.0.0",
|
||||||
|
"minipass": "^3.1.1",
|
||||||
|
"minipass-collect": "^1.0.2",
|
||||||
|
"minipass-flush": "^1.0.5",
|
||||||
|
"minipass-pipeline": "^1.2.2",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"p-map": "^4.0.0",
|
||||||
|
"promise-inflight": "^1.0.1",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"ssri": "^8.0.1",
|
||||||
|
"tar": "^6.0.2",
|
||||||
|
"unique-filename": "^1.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"lru-cache": {
|
||||||
|
"version": "6.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||||
|
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"p-map": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"aggregate-error": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema-utils": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/json-schema": "^7.0.6",
|
||||||
|
"ajv": "^6.12.5",
|
||||||
|
"ajv-keywords": "^3.5.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"serialize-javascript": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"randombytes": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ssri": {
|
||||||
|
"version": "8.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
|
||||||
|
"integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
@@ -18948,6 +19364,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"css-vars-ponyfill": {
|
||||||
|
"version": "2.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-vars-ponyfill/-/css-vars-ponyfill-2.4.3.tgz",
|
||||||
|
"integrity": "sha512-PBfIwjSu27s8kebu8taEYFM8ehVr8o2Qw4H4nSlJzHAJgcduAqxz4oPmYTJuzgauOKaWII9SHWStQ965fxsdZA=="
|
||||||
|
},
|
||||||
"css-what": {
|
"css-what": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||||
@@ -22407,6 +22828,24 @@
|
|||||||
"minipass": "^3.0.0"
|
"minipass": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"minizlib": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"mississippi": {
|
"mississippi": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||||
@@ -25512,6 +25951,40 @@
|
|||||||
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tar": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chownr": "^2.0.0",
|
||||||
|
"fs-minipass": "^2.0.0",
|
||||||
|
"minipass": "^3.0.0",
|
||||||
|
"minizlib": "^2.1.1",
|
||||||
|
"mkdirp": "^1.0.3",
|
||||||
|
"yallist": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chownr": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"mkdirp": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "4.8.0",
|
"version": "4.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
||||||
@@ -27088,6 +27561,11 @@
|
|||||||
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
"integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"whatwg-fetch": {
|
||||||
|
"version": "3.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
|
||||||
|
"integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA=="
|
||||||
|
},
|
||||||
"which": {
|
"which": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"ace-builds": "^1.4.7",
|
"ace-builds": "^1.4.7",
|
||||||
"clipboard": "^2.0.4",
|
"clipboard": "^2.0.4",
|
||||||
"core-js": "^3.9.1",
|
"core-js": "^3.9.1",
|
||||||
|
"css-vars-ponyfill": "^2.4.3",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"lodash.clonedeep": "^4.5.0",
|
"lodash.clonedeep": "^4.5.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
@@ -27,7 +28,8 @@
|
|||||||
"vue-lazyload": "^1.3.3",
|
"vue-lazyload": "^1.3.3",
|
||||||
"vue-router": "^3.1.3",
|
"vue-router": "^3.1.3",
|
||||||
"vuex": "^3.1.2",
|
"vuex": "^3.1.2",
|
||||||
"vuex-router-sync": "^5.0.0"
|
"vuex-router-sync": "^5.0.0",
|
||||||
|
"whatwg-fetch": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^4.1.2",
|
"@vue/cli-plugin-babel": "^4.1.2",
|
||||||
@@ -35,6 +37,7 @@
|
|||||||
"@vue/cli-service": "^4.1.2",
|
"@vue/cli-service": "^4.1.2",
|
||||||
"@vue/eslint-config-prettier": "^6.0.0",
|
"@vue/eslint-config-prettier": "^6.0.0",
|
||||||
"babel-eslint": "^10.1.0",
|
"babel-eslint": "^10.1.0",
|
||||||
|
"compression-webpack-plugin": "^6.0.3",
|
||||||
"eslint": "^6.7.2",
|
"eslint": "^6.7.2",
|
||||||
"eslint-plugin-prettier": "^3.3.1",
|
"eslint-plugin-prettier": "^3.3.1",
|
||||||
"eslint-plugin-vue": "^6.2.2",
|
"eslint-plugin-vue": "^6.2.2",
|
||||||
@@ -64,6 +67,6 @@
|
|||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
"not ie <= 8"
|
"not ie < 11"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<!-- Inject Some Variables and generate the manifest json -->
|
<!-- Inject Some Variables and generate the manifest json -->
|
||||||
<script>
|
<script>
|
||||||
window.FileBrowser = JSON.parse(`[{[ .Json ]}]`);
|
window.FileBrowser = JSON.parse('[{[ .Json ]}]');
|
||||||
|
|
||||||
var fullStaticURL = window.location.origin + window.FileBrowser.StaticURL;
|
var fullStaticURL = window.location.origin + window.FileBrowser.StaticURL;
|
||||||
var dynamicManifest = {
|
var dynamicManifest = {
|
||||||
@@ -77,7 +77,7 @@
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner {
|
#loading .spinner {
|
||||||
width: 70px;
|
width: 70px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner > div {
|
#loading .spinner > div {
|
||||||
width: 18px;
|
width: 18px;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
background-color: #333;
|
background-color: #333;
|
||||||
@@ -97,12 +97,12 @@
|
|||||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner .bounce1 {
|
#loading .spinner .bounce1 {
|
||||||
-webkit-animation-delay: -0.32s;
|
-webkit-animation-delay: -0.32s;
|
||||||
animation-delay: -0.32s;
|
animation-delay: -0.32s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spinner .bounce2 {
|
#loading .spinner .bounce2 {
|
||||||
-webkit-animation-delay: -0.16s;
|
-webkit-animation-delay: -0.16s;
|
||||||
animation-delay: -0.16s;
|
animation-delay: -0.16s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ body {
|
|||||||
#loading {
|
#loading {
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
}
|
}
|
||||||
#loading .spinner div, #previewer .loading .spinner div {
|
#loading .spinner div, main .spinner div {
|
||||||
background: var(--icon);
|
background: var(--icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
__webpack_public_path__ = window.FileBrowser.StaticURL + "/";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "app",
|
name: "app",
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|||||||
@@ -8,13 +8,18 @@ export async function fetchURL(url, opts) {
|
|||||||
|
|
||||||
let { headers, ...rest } = opts;
|
let { headers, ...rest } = opts;
|
||||||
|
|
||||||
const res = await fetch(`${baseURL}${url}`, {
|
let res;
|
||||||
headers: {
|
try {
|
||||||
"X-Auth": store.state.jwt,
|
res = await fetch(`${baseURL}${url}`, {
|
||||||
...headers,
|
headers: {
|
||||||
},
|
"X-Auth": store.state.jwt,
|
||||||
...rest,
|
...headers,
|
||||||
});
|
},
|
||||||
|
...rest,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return { status: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
if (res.headers.get("X-Renew-Token") === "true") {
|
if (res.headers.get("X-Renew-Token") === "true") {
|
||||||
await renew(store.state.jwt);
|
await renew(store.state.jwt);
|
||||||
|
|||||||
@@ -8,8 +8,6 @@
|
|||||||
@dragover="dragOver"
|
@dragover="dragOver"
|
||||||
@drop="drop"
|
@drop="drop"
|
||||||
@click="itemClick"
|
@click="itemClick"
|
||||||
@dblclick="dblclick"
|
|
||||||
@touchstart="touchstart"
|
|
||||||
:data-dir="isDir"
|
:data-dir="isDir"
|
||||||
:aria-label="name"
|
:aria-label="name"
|
||||||
:aria-selected="isSelected"
|
:aria-selected="isSelected"
|
||||||
@@ -96,7 +94,7 @@ export default {
|
|||||||
// reload the image when the file is replaced
|
// reload the image when the file is replaced
|
||||||
const key = Date.parse(this.modified);
|
const key = Date.parse(this.modified);
|
||||||
|
|
||||||
return `${baseURL}/api/preview/thumb/${path}?auth=${this.jwt}&inline=true&k=${key}`;
|
return `${baseURL}/api/preview/thumb/${path}?k=${key}&inline=true`;
|
||||||
},
|
},
|
||||||
isThumbsEnabled() {
|
isThumbsEnabled() {
|
||||||
return enableThumbs;
|
return enableThumbs;
|
||||||
@@ -153,13 +151,13 @@ export default {
|
|||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[i].url,
|
from: this.req.items[i].url,
|
||||||
to: this.url + this.req.items[i].name,
|
to: this.url + encodeURIComponent(this.req.items[i].name),
|
||||||
name: this.req.items[i].name,
|
name: this.req.items[i].name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let base = el.querySelector(".name").innerHTML + "/";
|
// Get url from ListingItem instance
|
||||||
let path = this.$route.path + base;
|
let path = el.__vue__.url;
|
||||||
let baseItems = (await api.fetch(path)).items;
|
let baseItems = (await api.fetch(path)).items;
|
||||||
|
|
||||||
let action = (overwrite, rename) => {
|
let action = (overwrite, rename) => {
|
||||||
@@ -200,6 +198,16 @@ export default {
|
|||||||
},
|
},
|
||||||
click: function (event) {
|
click: function (event) {
|
||||||
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault();
|
if (!this.singleClick && this.selectedCount !== 0) event.preventDefault();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.touches = 0;
|
||||||
|
}, 300);
|
||||||
|
|
||||||
|
this.touches++;
|
||||||
|
if (this.touches > 1) {
|
||||||
|
this.open();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
if (this.$store.state.selected.indexOf(this.index) !== -1) {
|
||||||
this.removeSelected(this.index);
|
this.removeSelected(this.index);
|
||||||
return;
|
return;
|
||||||
@@ -235,19 +243,6 @@ export default {
|
|||||||
this.resetSelected();
|
this.resetSelected();
|
||||||
this.addSelected(this.index);
|
this.addSelected(this.index);
|
||||||
},
|
},
|
||||||
dblclick: function () {
|
|
||||||
if (!this.singleClick) this.open();
|
|
||||||
},
|
|
||||||
touchstart() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.touches = 0;
|
|
||||||
}, 300);
|
|
||||||
|
|
||||||
this.touches++;
|
|
||||||
if (this.touches > 1) {
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
open: function () {
|
open: function () {
|
||||||
this.$router.push({ path: this.url });
|
this.$router.push({ path: this.url });
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<strong>{{ $t("prompts.size") }}:</strong>
|
<strong>{{ $t("prompts.size") }}:</strong>
|
||||||
<span id="content_length"></span> {{ humanSize }}
|
<span id="content_length"></span> {{ humanSize }}
|
||||||
</p>
|
</p>
|
||||||
<p v-if="selected.length < 2">
|
<p v-if="selected.length < 2" :title="modTime">
|
||||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -110,6 +110,9 @@ export default {
|
|||||||
|
|
||||||
return moment(this.req.items[this.selected[0]].modified).fromNow();
|
return moment(this.req.items[this.selected[0]].modified).fromNow();
|
||||||
},
|
},
|
||||||
|
modTime: function () {
|
||||||
|
return new Date(Date.parse(this.req.modified)).toLocaleString();
|
||||||
|
},
|
||||||
name: function () {
|
name: function () {
|
||||||
return this.selectedCount === 0
|
return this.selectedCount === 0
|
||||||
? this.req.name
|
? this.req.name
|
||||||
|
|||||||
@@ -43,6 +43,15 @@
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.share__box__element .button {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share__box__element .button i {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.share__box__items {
|
.share__box__items {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
flex: 10 0 25em;
|
flex: 10 0 25em;
|
||||||
|
|||||||
@@ -17,6 +17,48 @@
|
|||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main .spinner {
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 0;
|
||||||
|
padding: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .spinner > div {
|
||||||
|
width: .8em;
|
||||||
|
height: .8em;
|
||||||
|
margin: 0 .1em;
|
||||||
|
font-size: 1em;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-radius: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .spinner .bounce1 {
|
||||||
|
animation-delay: -0.32s;
|
||||||
|
}
|
||||||
|
|
||||||
|
main .spinner .bounce2 {
|
||||||
|
animation-delay: -0.16s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delayed {
|
||||||
|
animation: delayed linear 100ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes delayed {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
99% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* * * * * * * * * * * * * * * *
|
/* * * * * * * * * * * * * * * *
|
||||||
* ACTION *
|
* ACTION *
|
||||||
* * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * */
|
||||||
@@ -163,6 +205,34 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .preview .info {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 1.5em;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
#previewer .preview .info .title {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
#previewer .preview .info .title i {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: .1em;
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
#previewer .preview .info .button {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
#previewer .preview .info .button:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2)
|
||||||
|
}
|
||||||
|
#previewer .preview .info .button i {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 1.3em;
|
||||||
|
}
|
||||||
|
|
||||||
#previewer .pdf {
|
#previewer .pdf {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -204,6 +274,20 @@
|
|||||||
right: 0.5em;
|
right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#previewer .spinner {
|
||||||
|
text-align: center;
|
||||||
|
position: fixed;
|
||||||
|
top: calc(50% + 1.85em);
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#previewer .spinner > div {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* EDITOR */
|
/* EDITOR */
|
||||||
|
|
||||||
#editor-container {
|
#editor-container {
|
||||||
@@ -217,11 +301,6 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#previewer .loading {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#editor-container #editor {
|
#editor-container #editor {
|
||||||
height: calc(100vh - 8.4em);
|
height: calc(100vh - 8.4em);
|
||||||
}
|
}
|
||||||
@@ -283,7 +362,6 @@
|
|||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: rotate(-360deg);
|
|
||||||
transform: rotate(-360deg);
|
transform: rotate(-360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,8 @@
|
|||||||
"switchView": "Switch view",
|
"switchView": "Switch view",
|
||||||
"toggleSidebar": "Toggle sidebar",
|
"toggleSidebar": "Toggle sidebar",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"upload": "Upload"
|
"upload": "Upload",
|
||||||
|
"openFile": "Open file"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"downloadFile": "Download File",
|
"downloadFile": "Download File",
|
||||||
@@ -43,7 +44,8 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"forbidden": "You don't have permissions to access this.",
|
"forbidden": "You don't have permissions to access this.",
|
||||||
"internal": "Something really went wrong.",
|
"internal": "Something really went wrong.",
|
||||||
"notFound": "This location can't be reached."
|
"notFound": "This location can't be reached.",
|
||||||
|
"connection": "The server can't be reached."
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"body": "Body",
|
"body": "Body",
|
||||||
@@ -61,7 +63,8 @@
|
|||||||
"size": "Size",
|
"size": "Size",
|
||||||
"sortByLastModified": "Sort by last modified",
|
"sortByLastModified": "Sort by last modified",
|
||||||
"sortByName": "Sort by name",
|
"sortByName": "Sort by name",
|
||||||
"sortBySize": "Sort by size"
|
"sortBySize": "Sort by size",
|
||||||
|
"noPreview": "Preview is not available for this file."
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"click": "select file or directory",
|
"click": "select file or directory",
|
||||||
@@ -214,6 +217,7 @@
|
|||||||
"settingsUpdated": "Settings updated!",
|
"settingsUpdated": "Settings updated!",
|
||||||
"shareDuration": "Share Duration",
|
"shareDuration": "Share Duration",
|
||||||
"shareManagement": "Share Management",
|
"shareManagement": "Share Management",
|
||||||
|
"shareDeleted": "Share deleted!",
|
||||||
"singleClick": "Use single clicks to open files and directories",
|
"singleClick": "Use single clicks to open files and directories",
|
||||||
"themes": {
|
"themes": {
|
||||||
"dark": "Dark",
|
"dark": "Dark",
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import "whatwg-fetch";
|
||||||
|
import cssVars from "css-vars-ponyfill";
|
||||||
import { sync } from "vuex-router-sync";
|
import { sync } from "vuex-router-sync";
|
||||||
import store from "@/store";
|
import store from "@/store";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
@@ -7,6 +9,8 @@ import { recaptcha, loginPage } from "@/utils/constants";
|
|||||||
import { login, validateLogin } from "@/utils/auth";
|
import { login, validateLogin } from "@/utils/auth";
|
||||||
import App from "@/App";
|
import App from "@/App";
|
||||||
|
|
||||||
|
cssVars();
|
||||||
|
|
||||||
sync(store, router);
|
sync(store, router);
|
||||||
|
|
||||||
async function start() {
|
async function start() {
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ export function parseToken(token) {
|
|||||||
|
|
||||||
const data = JSON.parse(Base64.decode(parts[1]));
|
const data = JSON.parse(Base64.decode(parts[1]));
|
||||||
|
|
||||||
|
document.cookie = `auth=${token}; path=/`;
|
||||||
|
|
||||||
localStorage.setItem("jwt", token);
|
localStorage.setItem("jwt", token);
|
||||||
store.commit("setJWT", token);
|
store.commit("setJWT", token);
|
||||||
store.commit("setUser", data.user);
|
store.commit("setUser", data.user);
|
||||||
@@ -81,6 +83,8 @@ export async function signup(username, password) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function logout() {
|
export function logout() {
|
||||||
|
document.cookie = "auth=; expires=Thu, 01 Jan 1970 00:00:01 GMT; path=/";
|
||||||
|
|
||||||
store.commit("setJWT", "");
|
store.commit("setJWT", "");
|
||||||
store.commit("setUser", null);
|
store.commit("setUser", null);
|
||||||
localStorage.setItem("jwt", null);
|
localStorage.setItem("jwt", null);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
<header-bar v-if="showHeader" showMenu showLogo />
|
<header-bar v-if="showHeader" showMenu showLogo />
|
||||||
|
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<i class="material-icons">{{ icon }}</i>
|
<i class="material-icons">{{ info.icon }}</i>
|
||||||
<span>{{ message }}</span>
|
<span>{{ $t(info.message) }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -13,6 +13,10 @@
|
|||||||
import HeaderBar from "@/components/header/HeaderBar";
|
import HeaderBar from "@/components/header/HeaderBar";
|
||||||
|
|
||||||
const errors = {
|
const errors = {
|
||||||
|
0: {
|
||||||
|
icon: "cloud_off",
|
||||||
|
message: "errors.connection",
|
||||||
|
},
|
||||||
403: {
|
403: {
|
||||||
icon: "error",
|
icon: "error",
|
||||||
message: "errors.forbidden",
|
message: "errors.forbidden",
|
||||||
@@ -33,11 +37,17 @@ export default {
|
|||||||
HeaderBar,
|
HeaderBar,
|
||||||
},
|
},
|
||||||
props: ["errorCode", "showHeader"],
|
props: ["errorCode", "showHeader"],
|
||||||
data: function () {
|
computed: {
|
||||||
return {
|
code() {
|
||||||
icon: errors[this.errorCode].icon,
|
return this.errorCode === "0" ||
|
||||||
message: this.$t(errors[this.errorCode].message),
|
this.errorCode === "404" ||
|
||||||
};
|
this.errorCode === "403"
|
||||||
|
? parseInt(this.errorCode)
|
||||||
|
: 500;
|
||||||
|
},
|
||||||
|
info() {
|
||||||
|
return errors[this.code];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,10 +4,15 @@
|
|||||||
|
|
||||||
<breadcrumbs base="/files" />
|
<breadcrumbs base="/files" />
|
||||||
|
|
||||||
<errors v-if="error" :errorCode="errorCode" />
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
<component v-else-if="currentView" :is="currentView"></component>
|
<component v-else-if="currentView" :is="currentView"></component>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h2 class="message">
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
<span>{{ $t("files.loading") }}</span>
|
<span>{{ $t("files.loading") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,11 +67,6 @@ export default {
|
|||||||
return "preview";
|
return "preview";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
errorCode() {
|
|
||||||
return this.error.message === "404" || this.error.message === "403"
|
|
||||||
? parseInt(this.error.message)
|
|
||||||
: 500;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.fetchData();
|
this.fetchData();
|
||||||
@@ -116,7 +116,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$store.commit("updateRequest", res);
|
this.$store.commit("updateRequest", res);
|
||||||
document.title = res.name;
|
document.title = `${res.name} - ${this.$route.name}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e;
|
this.error = e;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -34,6 +34,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading">
|
||||||
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
|
<span>{{ $t("files.loading") }}</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -49,7 +60,7 @@ export default {
|
|||||||
HeaderBar,
|
HeaderBar,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["user"]),
|
...mapState(["user", "loading"]),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -19,7 +19,50 @@
|
|||||||
|
|
||||||
<breadcrumbs :base="'/share/' + hash" />
|
<breadcrumbs :base="'/share/' + hash" />
|
||||||
|
|
||||||
<div v-if="!loading">
|
<div v-if="loading">
|
||||||
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
|
<span>{{ $t("files.loading") }}</span>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="error">
|
||||||
|
<div v-if="error.message === '401'">
|
||||||
|
<div class="card floating" id="password">
|
||||||
|
<div v-if="attemptedPasswordLogin" class="share__wrong__password">
|
||||||
|
{{ $t("login.wrongCredentials") }}
|
||||||
|
</div>
|
||||||
|
<div class="card-title">
|
||||||
|
<h2>{{ $t("login.password") }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<input
|
||||||
|
v-focus
|
||||||
|
type="password"
|
||||||
|
:placeholder="$t('login.password')"
|
||||||
|
v-model="password"
|
||||||
|
@keyup.enter="fetchData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="card-action">
|
||||||
|
<button
|
||||||
|
class="button button--flat"
|
||||||
|
@click="fetchData"
|
||||||
|
:aria-label="$t('buttons.submit')"
|
||||||
|
:title="$t('buttons.submit')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.submit") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<errors v-else :errorCode="error.message" />
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
<div class="share">
|
<div class="share">
|
||||||
<div class="share__box share__box__info">
|
<div class="share__box share__box__info">
|
||||||
<div class="share__box__header">
|
<div class="share__box__header">
|
||||||
@@ -35,16 +78,30 @@
|
|||||||
<div class="share__box__element">
|
<div class="share__box__element">
|
||||||
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
<strong>{{ $t("prompts.displayName") }}</strong> {{ req.name }}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element">
|
<div class="share__box__element" :title="modTime">
|
||||||
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
<strong>{{ $t("prompts.lastModified") }}:</strong> {{ humanTime }}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element">
|
<div class="share__box__element">
|
||||||
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
<strong>{{ $t("prompts.size") }}:</strong> {{ humanSize }}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element share__box__center">
|
<div class="share__box__element share__box__center">
|
||||||
<a target="_blank" :href="link" class="button button--flat">{{
|
<a target="_blank" :href="link" class="button button--flat">
|
||||||
$t("buttons.download")
|
<div>
|
||||||
}}</a>
|
<i class="material-icons">file_download</i
|
||||||
|
>{{ $t("buttons.download") }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
:href="inlineLink"
|
||||||
|
class="button button--flat"
|
||||||
|
v-if="!req.isDir"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<i class="material-icons">open_in_new</i
|
||||||
|
>{{ $t("buttons.openFile") }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element share__box__center">
|
<div class="share__box__element share__box__center">
|
||||||
<qrcode-vue :value="fullLink" size="200" level="M"></qrcode-vue>
|
<qrcode-vue :value="fullLink" size="200" level="M"></qrcode-vue>
|
||||||
@@ -71,7 +128,11 @@
|
|||||||
readOnly
|
readOnly
|
||||||
>
|
>
|
||||||
</item>
|
</item>
|
||||||
<div v-if="req.items.length > showLimit" class="item">
|
<div
|
||||||
|
v-if="req.items.length > showLimit"
|
||||||
|
class="item"
|
||||||
|
@click="showLimit += 100"
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p class="name">+ {{ req.items.length - showLimit }}</p>
|
<p class="name">+ {{ req.items.length - showLimit }}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,39 +167,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="error">
|
|
||||||
<div v-if="error.message === '401'">
|
|
||||||
<div class="card floating" id="password">
|
|
||||||
<div v-if="attemptedPasswordLogin" class="share__wrong__password">
|
|
||||||
{{ $t("login.wrongCredentials") }}
|
|
||||||
</div>
|
|
||||||
<div class="card-title">
|
|
||||||
<h2>{{ $t("login.password") }}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-content">
|
|
||||||
<input
|
|
||||||
v-focus
|
|
||||||
type="password"
|
|
||||||
:placeholder="$t('login.password')"
|
|
||||||
v-model="password"
|
|
||||||
@keyup.enter="fetchData"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="card-action">
|
|
||||||
<button
|
|
||||||
class="button button--flat"
|
|
||||||
@click="fetchData"
|
|
||||||
:aria-label="$t('buttons.submit')"
|
|
||||||
:title="$t('buttons.submit')"
|
|
||||||
>
|
|
||||||
{{ $t("buttons.submit") }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<errors v-else :errorCode="errorCode" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -168,14 +196,18 @@ export default {
|
|||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
error: null,
|
error: null,
|
||||||
showLimit: 500,
|
showLimit: 100,
|
||||||
password: "",
|
password: "",
|
||||||
attemptedPasswordLogin: false,
|
attemptedPasswordLogin: false,
|
||||||
hash: null,
|
hash: null,
|
||||||
token: null,
|
token: null,
|
||||||
}),
|
}),
|
||||||
watch: {
|
watch: {
|
||||||
$route: "fetchData",
|
$route: function () {
|
||||||
|
this.showLimit = 100;
|
||||||
|
|
||||||
|
this.fetchData();
|
||||||
|
},
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
const hash = this.$route.params.pathMatch.split("/")[0];
|
const hash = this.$route.params.pathMatch.split("/")[0];
|
||||||
@@ -207,6 +239,11 @@ export default {
|
|||||||
const path = this.$route.path.split("/").splice(2).join("/");
|
const path = this.$route.path.split("/").splice(2).join("/");
|
||||||
return `${baseURL}/api/public/dl/${path}${queryArg}`;
|
return `${baseURL}/api/public/dl/${path}${queryArg}`;
|
||||||
},
|
},
|
||||||
|
inlineLink: function () {
|
||||||
|
let url = new URL(this.link);
|
||||||
|
url.searchParams.set("inline", "true");
|
||||||
|
return url.href;
|
||||||
|
},
|
||||||
fullLink: function () {
|
fullLink: function () {
|
||||||
return window.location.origin + this.link;
|
return window.location.origin + this.link;
|
||||||
},
|
},
|
||||||
@@ -220,10 +257,8 @@ export default {
|
|||||||
humanTime: function () {
|
humanTime: function () {
|
||||||
return moment(this.req.modified).fromNow();
|
return moment(this.req.modified).fromNow();
|
||||||
},
|
},
|
||||||
errorCode() {
|
modTime: function () {
|
||||||
return this.error.message === "404" || this.error.message === "403"
|
return new Date(Date.parse(this.req.modified)).toLocaleString();
|
||||||
? parseInt(this.error.message)
|
|
||||||
: 500;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -256,9 +291,11 @@ export default {
|
|||||||
this.token = file.token || "";
|
this.token = file.token || "";
|
||||||
|
|
||||||
this.updateRequest(file);
|
this.updateRequest(file);
|
||||||
this.setLoading(false);
|
document.title = `${file.name} - ${this.$route.name}`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e;
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyEvent(event) {
|
keyEvent(event) {
|
||||||
|
|||||||
@@ -114,8 +114,13 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="$store.state.loading">
|
<div v-if="loading">
|
||||||
<h2 class="message">
|
<h2 class="message delayed">
|
||||||
|
<div class="spinner">
|
||||||
|
<div class="bounce1"></div>
|
||||||
|
<div class="bounce2"></div>
|
||||||
|
<div class="bounce3"></div>
|
||||||
|
</div>
|
||||||
<span>{{ $t("files.loading") }}</span>
|
<span>{{ $t("files.loading") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -254,6 +259,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Vue from "vue";
|
||||||
import { mapState, mapGetters, mapMutations } from "vuex";
|
import { mapState, mapGetters, mapMutations } from "vuex";
|
||||||
import { users, files as api } from "@/api";
|
import { users, files as api } from "@/api";
|
||||||
import { enableExec } from "@/utils/constants";
|
import { enableExec } from "@/utils/constants";
|
||||||
@@ -279,10 +285,19 @@ export default {
|
|||||||
showLimit: 50,
|
showLimit: 50,
|
||||||
dragCounter: 0,
|
dragCounter: 0,
|
||||||
width: window.innerWidth,
|
width: window.innerWidth,
|
||||||
|
itemWeight: 0,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["req", "selected", "user", "show", "multiple", "selected"]),
|
...mapState([
|
||||||
|
"req",
|
||||||
|
"selected",
|
||||||
|
"user",
|
||||||
|
"show",
|
||||||
|
"multiple",
|
||||||
|
"selected",
|
||||||
|
"loading",
|
||||||
|
]),
|
||||||
...mapGetters(["selectedCount"]),
|
...mapGetters(["selectedCount"]),
|
||||||
nameSorted() {
|
nameSorted() {
|
||||||
return this.req.sorting.by === "name";
|
return this.req.sorting.by === "name";
|
||||||
@@ -362,8 +377,14 @@ export default {
|
|||||||
// Reset the show value
|
// Reset the show value
|
||||||
this.showLimit = 50;
|
this.showLimit = 50;
|
||||||
|
|
||||||
// Fill and fit the window with listing items
|
// Ensures that the listing is displayed
|
||||||
this.fillWindow(true);
|
Vue.nextTick(() => {
|
||||||
|
// How much every listing item affects the window height
|
||||||
|
this.setItemWeight();
|
||||||
|
|
||||||
|
// Fill and fit the window with listing items
|
||||||
|
this.fillWindow(true);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
@@ -393,7 +414,7 @@ export default {
|
|||||||
window.removeEventListener("scroll", this.scrollEvent);
|
window.removeEventListener("scroll", this.scrollEvent);
|
||||||
window.removeEventListener("resize", this.windowsResize);
|
window.removeEventListener("resize", this.windowsResize);
|
||||||
|
|
||||||
if (!this.user.perm.create) return;
|
if (this.user && !this.user.perm.create) return;
|
||||||
document.removeEventListener("dragover", this.preventDefault);
|
document.removeEventListener("dragover", this.preventDefault);
|
||||||
document.removeEventListener("dragenter", this.dragEnter);
|
document.removeEventListener("dragenter", this.dragEnter);
|
||||||
document.removeEventListener("dragleave", this.dragLeave);
|
document.removeEventListener("dragleave", this.dragLeave);
|
||||||
@@ -484,7 +505,7 @@ export default {
|
|||||||
for (let i of this.selected) {
|
for (let i of this.selected) {
|
||||||
items.push({
|
items.push({
|
||||||
from: this.req.items[i].url,
|
from: this.req.items[i].url,
|
||||||
name: encodeURIComponent(this.req.items[i].name),
|
name: this.req.items[i].name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,7 +530,7 @@ export default {
|
|||||||
const from = item.from.endsWith("/")
|
const from = item.from.endsWith("/")
|
||||||
? item.from.slice(0, -1)
|
? item.from.slice(0, -1)
|
||||||
: item.from;
|
: item.from;
|
||||||
const to = this.$route.path + item.name;
|
const to = this.$route.path + encodeURIComponent(item.name);
|
||||||
items.push({ from, to, name: item.name });
|
items.push({ from, to, name: item.name });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,22 +652,20 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let base = "";
|
let files = await upload.scanFiles(dt);
|
||||||
|
let items = this.req.items;
|
||||||
|
let path = this.$route.path.endsWith("/")
|
||||||
|
? this.$route.path
|
||||||
|
: this.$route.path + "/";
|
||||||
|
|
||||||
if (
|
if (
|
||||||
el !== null &&
|
el !== null &&
|
||||||
el.classList.contains("item") &&
|
el.classList.contains("item") &&
|
||||||
el.dataset.dir === "true"
|
el.dataset.dir === "true"
|
||||||
) {
|
) {
|
||||||
base = el.querySelector(".name").innerHTML + "/";
|
// Get url from ListingItem instance
|
||||||
}
|
path = el.__vue__.url;
|
||||||
|
|
||||||
let files = await upload.scanFiles(dt);
|
|
||||||
let path = this.$route.path.endsWith("/")
|
|
||||||
? this.$route.path + base
|
|
||||||
: this.$route.path + "/" + base;
|
|
||||||
let items = this.req.items;
|
|
||||||
|
|
||||||
if (base !== "") {
|
|
||||||
try {
|
try {
|
||||||
items = (await api.fetch(path)).items;
|
items = (await api.fetch(path)).items;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -793,26 +812,28 @@ export default {
|
|||||||
viewMode: this.user.viewMode === "mosaic" ? "list" : "mosaic",
|
viewMode: this.user.viewMode === "mosaic" ? "list" : "mosaic",
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
users.update(data, ["viewMode"]).catch(this.$showError);
|
||||||
await users.update(data, ["viewMode"]);
|
|
||||||
|
|
||||||
// Await ensures correct value for setItemWeight()
|
// Await ensures correct value for setItemWeight()
|
||||||
await this.$store.commit("updateUser", data);
|
await this.$store.commit("updateUser", data);
|
||||||
|
|
||||||
this.setItemWeight();
|
this.setItemWeight();
|
||||||
this.fillWindow();
|
this.fillWindow();
|
||||||
} catch (e) {
|
|
||||||
this.$showError(e);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
upload: function () {
|
upload: function () {
|
||||||
if (typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined") {
|
if (
|
||||||
|
typeof window.DataTransferItem !== "undefined" &&
|
||||||
|
typeof DataTransferItem.prototype.webkitGetAsEntry !== "undefined"
|
||||||
|
) {
|
||||||
this.$store.commit("showHover", "upload");
|
this.$store.commit("showHover", "upload");
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("upload-input").click();
|
document.getElementById("upload-input").click();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setItemWeight() {
|
setItemWeight() {
|
||||||
|
// Listing element is not displayed
|
||||||
|
if (this.$refs.listing == null) return;
|
||||||
|
|
||||||
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
let itemQuantity = this.req.numDirs + this.req.numFiles;
|
||||||
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
if (itemQuantity > this.showLimit) itemQuantity = this.showLimit;
|
||||||
|
|
||||||
|
|||||||
@@ -46,15 +46,14 @@
|
|||||||
</template>
|
</template>
|
||||||
</header-bar>
|
</header-bar>
|
||||||
|
|
||||||
<div class="loading" v-if="loading">
|
<div class="loading delayed" v-if="loading">
|
||||||
<div class="spinner">
|
<div class="spinner">
|
||||||
<div class="bounce1"></div>
|
<div class="bounce1"></div>
|
||||||
<div class="bounce2"></div>
|
<div class="bounce2"></div>
|
||||||
<div class="bounce3"></div>
|
<div class="bounce3"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<template v-else>
|
||||||
<template v-if="!loading">
|
|
||||||
<div class="preview">
|
<div class="preview">
|
||||||
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
<ExtendedImage v-if="req.type == 'image'" :src="raw"></ExtendedImage>
|
||||||
<audio
|
<audio
|
||||||
@@ -90,12 +89,31 @@
|
|||||||
class="pdf"
|
class="pdf"
|
||||||
:data="raw"
|
:data="raw"
|
||||||
></object>
|
></object>
|
||||||
<a v-else-if="req.type == 'blob'" :href="downloadUrl">
|
<div v-else-if="req.type == 'blob'" class="info">
|
||||||
<h2 class="message">
|
<div class="title">
|
||||||
{{ $t("buttons.download") }}
|
<i class="material-icons">feedback</i>
|
||||||
<i class="material-icons">file_download</i>
|
{{ $t("files.noPreview") }}
|
||||||
</h2>
|
</div>
|
||||||
</a>
|
<div>
|
||||||
|
<a target="_blank" :href="downloadUrl" class="button button--flat">
|
||||||
|
<div>
|
||||||
|
<i class="material-icons">file_download</i
|
||||||
|
>{{ $t("buttons.download") }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
:href="downloadUrl + '&inline=true'"
|
||||||
|
class="button button--flat"
|
||||||
|
v-if="!req.isDir"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<i class="material-icons">open_in_new</i
|
||||||
|
>{{ $t("buttons.openFile") }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -176,11 +194,9 @@ export default {
|
|||||||
if (this.req.type === "image" && !this.fullSize) {
|
if (this.req.type === "image" && !this.fullSize) {
|
||||||
return `${baseURL}/api/preview/big${url.encodePath(
|
return `${baseURL}/api/preview/big${url.encodePath(
|
||||||
this.req.path
|
this.req.path
|
||||||
)}?auth=${this.jwt}&k=${key}`;
|
)}?k=${key}`;
|
||||||
}
|
}
|
||||||
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${
|
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?k=${key}`;
|
||||||
this.jwt
|
|
||||||
}&k=${key}`;
|
|
||||||
},
|
},
|
||||||
raw() {
|
raw() {
|
||||||
return `${this.previewUrl}&inline=true`;
|
return `${this.previewUrl}&inline=true`;
|
||||||
@@ -258,7 +274,7 @@ export default {
|
|||||||
|
|
||||||
if (this.req.subtitles) {
|
if (this.req.subtitles) {
|
||||||
this.subtitles = this.req.subtitles.map(
|
this.subtitles = this.req.subtitles.map(
|
||||||
(sub) => `${baseURL}/api/raw${sub}?auth=${this.jwt}&inline=true`
|
(sub) => `${baseURL}/api/raw${sub}?inline=true`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row" v-if="settings !== null">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form class="card" @submit.prevent="save">
|
<form class="card" @submit.prevent="save">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
@@ -170,12 +171,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { settings as api } from "@/api";
|
import { settings as api } from "@/api";
|
||||||
|
import { enableExec } from "@/utils/constants";
|
||||||
import UserForm from "@/components/settings/UserForm";
|
import UserForm from "@/components/settings/UserForm";
|
||||||
import Rules from "@/components/settings/Rules";
|
import Rules from "@/components/settings/Rules";
|
||||||
import Themes from "@/components/settings/Themes";
|
import Themes from "@/components/settings/Themes";
|
||||||
import { enableExec } from "@/utils/constants";
|
import Errors from "@/views/Errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "settings",
|
name: "settings",
|
||||||
@@ -183,19 +185,23 @@ export default {
|
|||||||
Themes,
|
Themes,
|
||||||
UserForm,
|
UserForm,
|
||||||
Rules,
|
Rules,
|
||||||
|
Errors,
|
||||||
},
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
originalSettings: null,
|
originalSettings: null,
|
||||||
settings: null,
|
settings: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(["user"]),
|
...mapState(["user", "loading"]),
|
||||||
isExecEnabled: () => enableExec,
|
isExecEnabled: () => enableExec,
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
try {
|
try {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
const original = await api.get();
|
const original = await api.get();
|
||||||
let settings = { ...original, commands: [] };
|
let settings = { ...original, commands: [] };
|
||||||
|
|
||||||
@@ -211,10 +217,13 @@ export default {
|
|||||||
this.originalSettings = original;
|
this.originalSettings = original;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
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);
|
||||||
|
|||||||
@@ -103,12 +103,13 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
this.setLoading(false);
|
||||||
this.locale = this.user.locale;
|
this.locale = this.user.locale;
|
||||||
this.hideDotfiles = this.user.hideDotfiles;
|
this.hideDotfiles = this.user.hideDotfiles;
|
||||||
this.singleClick = this.user.singleClick;
|
this.singleClick = this.user.singleClick;
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["updateUser"]),
|
...mapMutations(["updateUser", "setLoading"]),
|
||||||
async updatePassword(event) {
|
async updatePassword(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t("settings.shareManagement") }}</h2>
|
<h2>{{ $t("settings.shareManagement") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content full">
|
<div class="card-content full" v-if="links.length > 0">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{{ $t("settings.path") }}</th>
|
<th>{{ $t("settings.path") }}</th>
|
||||||
@@ -52,6 +53,10 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<h2 class="message" v-else>
|
||||||
|
<i class="material-icons">sentiment_dissatisfied</i>
|
||||||
|
<span>{{ $t("files.lonely") }}</span>
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,21 +64,28 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { share as api, users } from "@/api";
|
import { share as api, users } from "@/api";
|
||||||
import moment from "moment";
|
|
||||||
import { baseURL } from "@/utils/constants";
|
import { baseURL } from "@/utils/constants";
|
||||||
|
import { mapState, mapMutations } from "vuex";
|
||||||
|
import moment from "moment";
|
||||||
import Clipboard from "clipboard";
|
import Clipboard from "clipboard";
|
||||||
import { mapState } from "vuex";
|
import Errors from "@/views/Errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "shares",
|
name: "shares",
|
||||||
computed: mapState(["user"]),
|
components: {
|
||||||
|
Errors,
|
||||||
|
},
|
||||||
|
computed: mapState(["user", "loading"]),
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
links: [],
|
links: [],
|
||||||
clip: null,
|
clip: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let links = await api.list();
|
let links = await api.list();
|
||||||
if (this.user.perm.admin) {
|
if (this.user.perm.admin) {
|
||||||
@@ -87,7 +99,9 @@ export default {
|
|||||||
}
|
}
|
||||||
this.links = links;
|
this.links = links;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -100,6 +114,7 @@ export default {
|
|||||||
this.clip.destroy();
|
this.clip.destroy();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
deleteLink: async function (event, link) {
|
deleteLink: async function (event, link) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@@ -108,8 +123,13 @@ export default {
|
|||||||
confirm: () => {
|
confirm: () => {
|
||||||
this.$store.commit("closeHovers");
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
api.remove(link.hash);
|
try {
|
||||||
this.links = this.links.filter((item) => item.hash !== link.hash);
|
api.remove(link.hash);
|
||||||
|
this.links = this.links.filter((item) => item.hash !== link.hash);
|
||||||
|
this.$showSuccess(this.$t("settings.shareDeleted"));
|
||||||
|
} catch (e) {
|
||||||
|
this.$showError(e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<form v-if="loaded" @submit="save" class="card">
|
<form @submit="save" class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2 v-if="user.id === 0">{{ $t("settings.newUser") }}</h2>
|
<h2 v-if="user.id === 0">{{ $t("settings.newUser") }}</h2>
|
||||||
<h2 v-else>{{ $t("settings.user") }} {{ user.username }}</h2>
|
<h2 v-else>{{ $t("settings.user") }} {{ user.username }}</h2>
|
||||||
@@ -55,21 +56,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapMutations } from "vuex";
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { users as api, settings } from "@/api";
|
import { users as api, settings } from "@/api";
|
||||||
import UserForm from "@/components/settings/UserForm";
|
import UserForm from "@/components/settings/UserForm";
|
||||||
|
import Errors from "@/views/Errors";
|
||||||
import deepClone from "lodash.clonedeep";
|
import deepClone from "lodash.clonedeep";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "user",
|
name: "user",
|
||||||
components: {
|
components: {
|
||||||
UserForm,
|
UserForm,
|
||||||
|
Errors,
|
||||||
},
|
},
|
||||||
data: () => {
|
data: () => {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
originalUser: null,
|
originalUser: null,
|
||||||
user: {},
|
user: {},
|
||||||
loaded: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@@ -79,6 +82,7 @@ export default {
|
|||||||
isNew() {
|
isNew() {
|
||||||
return this.$route.path === "/settings/users/new";
|
return this.$route.path === "/settings/users/new";
|
||||||
},
|
},
|
||||||
|
...mapState(["loading"]),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route: "fetchData",
|
$route: "fetchData",
|
||||||
@@ -88,8 +92,10 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations(["closeHovers", "showHover", "setUser"]),
|
...mapMutations(["closeHovers", "showHover", "setUser", "setLoading"]),
|
||||||
async fetchData() {
|
async fetchData() {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (this.isNew) {
|
if (this.isNew) {
|
||||||
let { defaults } = await settings.get();
|
let { defaults } = await settings.get();
|
||||||
@@ -105,10 +111,10 @@ export default {
|
|||||||
const id = this.$route.params.pathMatch;
|
const id = this.$route.params.pathMatch;
|
||||||
this.user = { ...(await api.get(id)) };
|
this.user = { ...(await api.get(id)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loaded = true;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$router.push({ path: "/settings/users/new" });
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deletePrompt() {
|
deletePrompt() {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<errors v-if="error" :errorCode="error.message" />
|
||||||
|
<div class="row" v-else-if="!loading">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
@@ -41,21 +42,37 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapState, mapMutations } from "vuex";
|
||||||
import { users as api } from "@/api";
|
import { users as api } from "@/api";
|
||||||
|
import Errors from "@/views/Errors";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "users",
|
name: "users",
|
||||||
|
components: {
|
||||||
|
Errors,
|
||||||
|
},
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
error: null,
|
||||||
users: [],
|
users: [],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
this.setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.users = await api.getAll();
|
this.users = await api.getAll();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e);
|
this.error = e;
|
||||||
|
} finally {
|
||||||
|
this.setLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(["loading"]),
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(["setLoading"]),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
|
const CompressionPlugin = require("compression-webpack-plugin");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
runtimeCompiler: true,
|
runtimeCompiler: true,
|
||||||
publicPath: "[{[ .StaticURL ]}]",
|
publicPath: "[{[ .StaticURL ]}]",
|
||||||
parallel: 2,
|
parallel: 2,
|
||||||
|
configureWebpack: {
|
||||||
|
plugins: [
|
||||||
|
new CompressionPlugin({
|
||||||
|
include: /\.js$/,
|
||||||
|
deleteOriginalAssets: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
11
http/auth.go
11
http/auth.go
@@ -48,11 +48,16 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auth := r.URL.Query().Get("auth")
|
auth := r.URL.Query().Get("auth")
|
||||||
if auth == "" {
|
if auth != "" && strings.Count(auth, ".") == 2 {
|
||||||
return "", request.ErrNoTokenInRequest
|
return auth, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return auth, nil
|
cookie, _ := r.Cookie("auth")
|
||||||
|
if cookie != nil && strings.Count(cookie.Value, ".") == 2 {
|
||||||
|
return cookie.Value, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", request.ErrNoTokenInRequest
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUser(fn handleFunc) handleFunc {
|
func withUser(fn handleFunc) handleFunc {
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ func (d *data) Check(path string) bool {
|
|||||||
|
|
||||||
func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
|
func handle(fn handleFunc, prefix string, store *storage.Storage, server *settings.Server) http.Handler {
|
||||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
|
||||||
settings, err := store.Settings.Get()
|
settings, err := store.Settings.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("ERROR: couldn't get settings: %v\n", err)
|
log.Fatalf("ERROR: couldn't get settings: %v\n", err)
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ func NewHandler(
|
|||||||
server.Clean()
|
server.Clean()
|
||||||
|
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
|
r.Use(func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Security-Policy", `default-src 'self'`)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
})
|
||||||
index, static := getStaticHandlers(store, server, assetsFs)
|
index, static := getStaticHandlers(store, server, assetsFs)
|
||||||
|
|
||||||
// NOTE: This fixes the issue where it would redirect if people did not put a
|
// NOTE: This fixes the issue where it would redirect if people did not put a
|
||||||
@@ -57,7 +63,7 @@ func NewHandler(
|
|||||||
api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
|
api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
|
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
|
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
|
||||||
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler, "/api/resources")).Methods("PATCH")
|
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
|
||||||
|
|
||||||
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET")
|
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET")
|
||||||
api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET")
|
api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET")
|
||||||
|
|||||||
@@ -71,27 +71,38 @@ func previewHandler(imgSvc ImgService, fileCache FileCache, enableThumbnails, re
|
|||||||
func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgService, fileCache FileCache,
|
func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgService, fileCache FileCache,
|
||||||
file *files.FileInfo, previewSize PreviewSize, enableThumbnails, resizePreview bool) (int, error) {
|
file *files.FileInfo, previewSize PreviewSize, enableThumbnails, resizePreview bool) (int, error) {
|
||||||
format, err := imgSvc.FormatFromExtension(file.Extension)
|
format, err := imgSvc.FormatFromExtension(file.Extension)
|
||||||
|
|
||||||
|
// Unsupported extensions directly return the raw data
|
||||||
|
if err == img.ErrUnsupportedFormat || format == img.FormatGif {
|
||||||
|
return rawFileHandler(w, r, file)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Unsupported extensions directly return the raw data
|
|
||||||
if err == img.ErrUnsupportedFormat {
|
|
||||||
return rawFileHandler(w, r, file)
|
|
||||||
}
|
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
|
cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
|
||||||
cachedFile, ok, err := fileCache.Load(r.Context(), cacheKey)
|
resizedImage, ok, err := fileCache.Load(r.Context(), cacheKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
if ok {
|
if !ok {
|
||||||
_, _ = w.Write(cachedFile)
|
resizedImage, err = createPreview(imgSvc, fileCache, file, previewSize, enableThumbnails, resizePreview)
|
||||||
return 0, nil
|
if err != nil {
|
||||||
|
return errToStatus(err), err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Cache-Control", "private")
|
||||||
|
http.ServeContent(w, r, file.Name, file.ModTime, bytes.NewReader(resizedImage))
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createPreview(imgSvc ImgService, fileCache FileCache,
|
||||||
|
file *files.FileInfo, previewSize PreviewSize, enableThumbnails, resizePreview bool) ([]byte, error) {
|
||||||
fd, err := file.Fs.Open(file.Path)
|
fd, err := file.Fs.Open(file.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
|
||||||
@@ -102,7 +113,7 @@ func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgServic
|
|||||||
)
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case previewSize == PreviewSizeBig && resizePreview && format != img.FormatGif:
|
case previewSize == PreviewSizeBig && resizePreview:
|
||||||
width = 1080
|
width = 1080
|
||||||
height = 1080
|
height = 1080
|
||||||
options = append(options, img.WithMode(img.ResizeModeFit), img.WithQuality(img.QualityMedium))
|
options = append(options, img.WithMode(img.ResizeModeFit), img.WithQuality(img.QualityMedium))
|
||||||
@@ -111,26 +122,22 @@ func handleImagePreview(w http.ResponseWriter, r *http.Request, imgSvc ImgServic
|
|||||||
height = 128
|
height = 128
|
||||||
options = append(options, img.WithMode(img.ResizeModeFill), img.WithQuality(img.QualityLow), img.WithFormat(img.FormatJpeg))
|
options = append(options, img.WithMode(img.ResizeModeFill), img.WithQuality(img.QualityLow), img.WithFormat(img.FormatJpeg))
|
||||||
default:
|
default:
|
||||||
if _, err := rawFileHandler(w, r, file); err != nil {
|
return nil, img.ErrUnsupportedFormat
|
||||||
return errToStatus(err), err
|
|
||||||
}
|
|
||||||
return 0, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
if err := imgSvc.Resize(context.Background(), fd, width, height, buf, options...); err != nil {
|
if err := imgSvc.Resize(context.Background(), fd, width, height, buf, options...); err != nil {
|
||||||
return 0, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
cacheKey := previewCacheKey(file.Path, file.ModTime.Unix(), previewSize)
|
||||||
if err := fileCache.Store(context.Background(), cacheKey, buf.Bytes()); err != nil {
|
if err := fileCache.Store(context.Background(), cacheKey, buf.Bytes()); err != nil {
|
||||||
fmt.Printf("failed to cache resized image: %v", err)
|
fmt.Printf("failed to cache resized image: %v", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, _ = w.Write(buf.Bytes())
|
return buf.Bytes(), nil
|
||||||
|
|
||||||
return 0, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewCacheKey(fPath string, fTime int64, previewSize PreviewSize) string {
|
func previewCacheKey(fPath string, fTime int64, previewSize PreviewSize) string {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
|
|||||||
Fs: d.user.Fs,
|
Fs: d.user.Fs,
|
||||||
Path: link.Path,
|
Path: link.Path,
|
||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: false,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
Token: link.Token,
|
Token: link.Token,
|
||||||
|
|||||||
33
http/raw.go
33
http/raw.go
@@ -1,9 +1,8 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
gopath "path"
|
gopath "path"
|
||||||
@@ -11,7 +10,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/mholt/archiver"
|
"github.com/mholt/archiver"
|
||||||
"github.com/spf13/afero"
|
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/files"
|
"github.com/filebrowser/filebrowser/v2/files"
|
||||||
"github.com/filebrowser/filebrowser/v2/fileutils"
|
"github.com/filebrowser/filebrowser/v2/fileutils"
|
||||||
@@ -117,19 +115,16 @@ func addFile(ar archiver.Writer, d *data, path, commonPath string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
if !info.IsDir() && !info.Mode().IsRegular() {
|
||||||
file afero.File
|
return nil
|
||||||
arcReadCloser = ioutil.NopCloser(&bytes.Buffer{})
|
|
||||||
)
|
|
||||||
if !files.IsNamedPipe(info.Mode()) {
|
|
||||||
file, err = d.user.Fs.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
arcReadCloser = file
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file, err := d.user.Fs.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
if path != commonPath {
|
if path != commonPath {
|
||||||
filename := strings.TrimPrefix(path, commonPath)
|
filename := strings.TrimPrefix(path, commonPath)
|
||||||
filename = strings.TrimPrefix(filename, string(filepath.Separator))
|
filename = strings.TrimPrefix(filename, string(filepath.Separator))
|
||||||
@@ -138,7 +133,7 @@ func addFile(ar archiver.Writer, d *data, path, commonPath string) error {
|
|||||||
FileInfo: info,
|
FileInfo: info,
|
||||||
CustomName: filename,
|
CustomName: filename,
|
||||||
},
|
},
|
||||||
ReadCloser: arcReadCloser,
|
ReadCloser: file,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -152,9 +147,10 @@ func addFile(ar archiver.Writer, d *data, path, commonPath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
err = addFile(ar, d, filepath.Join(path, name), commonPath)
|
fPath := filepath.Join(path, name)
|
||||||
|
err = addFile(ar, d, fPath, commonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
log.Printf("Failed to archive %s: %v", fPath, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +192,7 @@ func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files.
|
|||||||
for _, fname := range filenames {
|
for _, fname := range filenames {
|
||||||
err = addFile(ar, d, fname, commonDir)
|
err = addFile(ar, d, fname, commonDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
log.Printf("Failed to archive %s: %v", fname, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +208,7 @@ func rawFileHandler(w http.ResponseWriter, r *http.Request, file *files.FileInfo
|
|||||||
|
|
||||||
setContentDisposition(w, r, file)
|
setContentDisposition(w, r, file)
|
||||||
|
|
||||||
|
w.Header().Set("Cache-Control", "private")
|
||||||
http.ServeContent(w, r, file.Name, file.ModTime, fd)
|
http.ServeContent(w, r, file.Name, file.ModTime, fd)
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|||||||
174
http/resource.go
174
http/resource.go
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
@@ -27,6 +26,7 @@ var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
|||||||
Expand: true,
|
Expand: true,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
|
Content: true,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
@@ -63,7 +63,7 @@ func resourceDeleteHandler(fileCache FileCache) handleFunc {
|
|||||||
Fs: d.user.Fs,
|
Fs: d.user.Fs,
|
||||||
Path: r.URL.Path,
|
Path: r.URL.Path,
|
||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: false,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
})
|
})
|
||||||
@@ -95,13 +95,9 @@ func resourcePostHandler(fileCache FileCache) handleFunc {
|
|||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_, _ = io.Copy(ioutil.Discard, r.Body)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 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, 0775)
|
err := d.user.Fs.MkdirAll(r.URL.Path, 0775) //nolint:gomnd
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +105,7 @@ func resourcePostHandler(fileCache FileCache) handleFunc {
|
|||||||
Fs: d.user.Fs,
|
Fs: d.user.Fs,
|
||||||
Path: r.URL.Path,
|
Path: r.URL.Path,
|
||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: false,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
})
|
})
|
||||||
@@ -153,16 +149,20 @@ var resourcePutHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
|||||||
return http.StatusForbidden, nil
|
return http.StatusForbidden, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
|
||||||
_, _ = io.Copy(ioutil.Discard, r.Body)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Only allow PUT for files.
|
// Only allow PUT for files.
|
||||||
if strings.HasSuffix(r.URL.Path, "/") {
|
if strings.HasSuffix(r.URL.Path, "/") {
|
||||||
return http.StatusMethodNotAllowed, nil
|
return http.StatusMethodNotAllowed, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.RunHook(func() error {
|
exists, err := afero.Exists(d.user.Fs, r.URL.Path)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
if !exists {
|
||||||
|
return http.StatusNotFound, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
if writeErr != nil {
|
if writeErr != nil {
|
||||||
return writeErr
|
return writeErr
|
||||||
@@ -173,71 +173,53 @@ var resourcePutHandler = withUser(func(w http.ResponseWriter, r *http.Request, d
|
|||||||
return nil
|
return nil
|
||||||
}, "save", r.URL.Path, "", d.user)
|
}, "save", r.URL.Path, "", d.user)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
_ = d.user.Fs.RemoveAll(r.URL.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
})
|
})
|
||||||
|
|
||||||
var resourcePatchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
func resourcePatchHandler(fileCache FileCache) handleFunc {
|
||||||
src := r.URL.Path
|
return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||||
dst := r.URL.Query().Get("destination")
|
src := r.URL.Path
|
||||||
action := r.URL.Query().Get("action")
|
dst := r.URL.Query().Get("destination")
|
||||||
dst, err := url.QueryUnescape(dst)
|
action := r.URL.Query().Get("action")
|
||||||
if !d.Check(src) || !d.Check(dst) {
|
dst, err := url.QueryUnescape(dst)
|
||||||
return http.StatusForbidden, nil
|
if !d.Check(src) || !d.Check(dst) {
|
||||||
}
|
return http.StatusForbidden, nil
|
||||||
if err != nil {
|
}
|
||||||
|
if err != nil {
|
||||||
|
return errToStatus(err), err
|
||||||
|
}
|
||||||
|
if dst == "/" || src == "/" {
|
||||||
|
return http.StatusForbidden, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = checkParent(src, dst)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusBadRequest, err
|
||||||
|
}
|
||||||
|
|
||||||
|
override := r.URL.Query().Get("override") == "true"
|
||||||
|
rename := r.URL.Query().Get("rename") == "true"
|
||||||
|
if !override && !rename {
|
||||||
|
if _, err = d.user.Fs.Stat(dst); err == nil {
|
||||||
|
return http.StatusConflict, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rename {
|
||||||
|
dst = addVersionSuffix(dst, d.user.Fs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Permission for overwriting the file
|
||||||
|
if override && !d.user.Perm.Modify {
|
||||||
|
return http.StatusForbidden, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = d.RunHook(func() error {
|
||||||
|
return patchAction(r.Context(), action, src, dst, d, fileCache)
|
||||||
|
}, action, src, dst, d.user)
|
||||||
|
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
})
|
||||||
if dst == "/" || src == "/" {
|
}
|
||||||
return http.StatusForbidden, nil
|
|
||||||
}
|
|
||||||
if err = checkParent(src, dst); err != nil {
|
|
||||||
return http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
override := r.URL.Query().Get("override") == "true"
|
|
||||||
rename := r.URL.Query().Get("rename") == "true"
|
|
||||||
if !override && !rename {
|
|
||||||
if _, err = d.user.Fs.Stat(dst); err == nil {
|
|
||||||
return http.StatusConflict, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if rename {
|
|
||||||
dst = addVersionSuffix(dst, d.user.Fs)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Permission for overwriting the file
|
|
||||||
if override && !d.user.Perm.Modify {
|
|
||||||
return http.StatusForbidden, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = d.RunHook(func() error {
|
|
||||||
switch action {
|
|
||||||
// TODO: use enum
|
|
||||||
case "copy":
|
|
||||||
if !d.user.Perm.Create {
|
|
||||||
return errors.ErrPermissionDenied
|
|
||||||
}
|
|
||||||
|
|
||||||
return fileutils.Copy(d.user.Fs, src, dst)
|
|
||||||
case "rename":
|
|
||||||
if !d.user.Perm.Rename {
|
|
||||||
return errors.ErrPermissionDenied
|
|
||||||
}
|
|
||||||
src = path.Clean("/" + src)
|
|
||||||
dst = path.Clean("/" + dst)
|
|
||||||
|
|
||||||
return fileutils.MoveFile(d.user.Fs, src, dst)
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
|
|
||||||
}
|
|
||||||
}, action, src, dst, d.user)
|
|
||||||
|
|
||||||
return errToStatus(err), err
|
|
||||||
})
|
|
||||||
|
|
||||||
func checkParent(src, dst string) error {
|
func checkParent(src, dst string) error {
|
||||||
rel, err := filepath.Rel(src, dst)
|
rel, err := filepath.Rel(src, dst)
|
||||||
@@ -273,12 +255,12 @@ func addVersionSuffix(source string, fs afero.Fs) string {
|
|||||||
|
|
||||||
func writeFile(fs afero.Fs, dst string, in io.Reader) (os.FileInfo, error) {
|
func writeFile(fs afero.Fs, dst string, in io.Reader) (os.FileInfo, error) {
|
||||||
dir, _ := path.Split(dst)
|
dir, _ := path.Split(dst)
|
||||||
err := fs.MkdirAll(dir, 0775)
|
err := fs.MkdirAll(dir, 0775) //nolint:gomnd
|
||||||
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, 0775)
|
file, err := fs.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0775) //nolint:gomnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -308,3 +290,43 @@ func delThumbs(ctx context.Context, fileCache FileCache, file *files.FileInfo) e
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func patchAction(ctx context.Context, action, src, dst string, d *data, fileCache FileCache) error {
|
||||||
|
switch action {
|
||||||
|
// TODO: use enum
|
||||||
|
case "copy":
|
||||||
|
if !d.user.Perm.Create {
|
||||||
|
return errors.ErrPermissionDenied
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileutils.Copy(d.user.Fs, src, dst)
|
||||||
|
case "rename":
|
||||||
|
if !d.user.Perm.Rename {
|
||||||
|
return errors.ErrPermissionDenied
|
||||||
|
}
|
||||||
|
src = path.Clean("/" + src)
|
||||||
|
dst = path.Clean("/" + dst)
|
||||||
|
|
||||||
|
file, err := files.NewFileInfo(files.FileOptions{
|
||||||
|
Fs: d.user.Fs,
|
||||||
|
Path: src,
|
||||||
|
Modify: d.user.Perm.Modify,
|
||||||
|
Expand: false,
|
||||||
|
ReadHeader: false,
|
||||||
|
Checker: d,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete thumbnails
|
||||||
|
err = delThumbs(ctx, fileCache, file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileutils.MoveFile(d.user.Fs, src, dst)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported action %s: %w", action, errors.ErrInvalidRequestParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
|||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes := make([]byte, 6)
|
bytes := make([]byte, 6) //nolint:gomnd
|
||||||
_, err := rand.Read(bytes)
|
_, err := rand.Read(bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
@@ -129,7 +129,7 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
|||||||
|
|
||||||
var token string
|
var token string
|
||||||
if len(hash) > 0 {
|
if len(hash) > 0 {
|
||||||
tokenBuffer := make([]byte, 96)
|
tokenBuffer := make([]byte, 96) //nolint:gomnd
|
||||||
if _, err := rand.Read(tokenBuffer); err != nil {
|
if _, err := rand.Read(tokenBuffer); err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package http
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -71,12 +72,12 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := json.MarshalIndent(data, "", " ")
|
b, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
data["Json"] = string(b)
|
data["Json"] = strings.ReplaceAll(string(b), `'`, `\'`)
|
||||||
|
|
||||||
fileContents, err := fs.ReadFile(fSys, file)
|
fileContents, err := fs.ReadFile(fSys, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -109,6 +110,9 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
|||||||
return http.StatusNotFound, nil
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxAge = 86400 // 1 day
|
||||||
|
w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%v", maxAge))
|
||||||
|
|
||||||
if d.settings.Branding.Files != "" {
|
if d.settings.Branding.Files != "" {
|
||||||
if strings.HasPrefix(r.URL.Path, "img/") {
|
if strings.HasPrefix(r.URL.Path, "img/") {
|
||||||
fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
|
fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
|
||||||
@@ -127,7 +131,19 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
|||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return handleWithStaticData(w, r, d, assetsFs, r.URL.Path, "application/javascript; charset=utf-8")
|
fileContents, err := fs.ReadFile(assetsFs, r.URL.Path+".gz")
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusNotFound, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Encoding", "gzip")
|
||||||
|
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||||
|
|
||||||
|
if _, err := w.Write(fileContents); err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
}, "/static/", store, server)
|
}, "/static/", store, server)
|
||||||
|
|
||||||
return index, static
|
return index, static
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type modifyUserRequest struct {
|
|||||||
|
|
||||||
func getUserID(r *http.Request) (uint, error) {
|
func getUserID(r *http.Request) (uint, error) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
i, err := strconv.ParseUint(vars["id"], 10, 0)
|
i, err := strconv.ParseUint(vars["id"], 10, 0) //nolint:gomnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -138,7 +138,7 @@ var userPostHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *
|
|||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Location", "/settings/users/"+strconv.FormatUint(uint64(req.Data.ID), 10))
|
w.Header().Set("Location", "/settings/users/"+strconv.FormatUint(uint64(req.Data.ID), 10)) //nolint:gomnd
|
||||||
return http.StatusCreated, nil
|
return http.StatusCreated, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -174,6 +174,8 @@ func (s *Service) Resize(ctx context.Context, in io.Reader, width, height int, o
|
|||||||
switch config.resizeMode {
|
switch config.resizeMode {
|
||||||
case ResizeModeFill:
|
case ResizeModeFill:
|
||||||
img = imaging.Fill(img, width, height, imaging.Center, config.quality.resampleFilter())
|
img = imaging.Fill(img, width, height, imaging.Center, config.quality.resampleFilter())
|
||||||
|
case ResizeModeFit:
|
||||||
|
fallthrough //nolint:gocritic
|
||||||
default:
|
default:
|
||||||
img = imaging.Fit(img, width, height, config.quality.resampleFilter())
|
img = imaging.Fit(img, width, height, config.quality.resampleFilter())
|
||||||
}
|
}
|
||||||
@@ -205,7 +207,7 @@ func getEmbeddedThumbnail(in io.Reader) ([]byte, io.Reader, error) {
|
|||||||
|
|
||||||
offset := 0
|
offset := 0
|
||||||
offsets := []int{12, 30}
|
offsets := []int{12, 30}
|
||||||
head := make([]byte, 0xffff)
|
head := make([]byte, 0xffff) //nolint:gomnd
|
||||||
|
|
||||||
_, err := r.Read(head)
|
_, err := r.Read(head)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ func (s *Server) Clean() {
|
|||||||
s.BaseURL = strings.TrimSuffix(s.BaseURL, "/")
|
s.BaseURL = strings.TrimSuffix(s.BaseURL, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateKey generates a key of 256 bits.
|
// GenerateKey generates a key of 512 bits.
|
||||||
func GenerateKey() ([]byte, error) {
|
func GenerateKey() ([]byte, error) {
|
||||||
b := make([]byte, 64)
|
b := make([]byte, 64) //nolint:gomnd
|
||||||
_, err := rand.Read(b)
|
_, err := rand.Read(b)
|
||||||
// Note that err == nil only if we read len(b) bytes.
|
// Note that err == nil only if we read len(b) bytes.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func NewStorage(db *storm.DB) (*storage.Storage, error) {
|
|||||||
settingsStore := settings.NewStorage(settingsBackend{db: db})
|
settingsStore := settings.NewStorage(settingsBackend{db: db})
|
||||||
authStore := auth.NewStorage(authBackend{db: db}, userStore)
|
authStore := auth.NewStorage(authBackend{db: db}, userStore)
|
||||||
|
|
||||||
err := save(db, "version", 2)
|
err := save(db, "version", 2) //nolint:gomnd
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user