Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1529e796df | ||
|
|
d4b904b92b | ||
|
|
12d4177823 | ||
|
|
8142b32f38 | ||
|
|
c5abbb4e1c | ||
|
|
65ac73414f | ||
|
|
ede4213c8e | ||
|
|
b60d291490 | ||
|
|
b9ede79888 | ||
|
|
3d2cb838d1 | ||
|
|
778734419d | ||
|
|
be8683f556 | ||
|
|
c3450f4614 | ||
|
|
5881bc9ab0 |
@@ -23,7 +23,7 @@ jobs:
|
|||||||
- '*'
|
- '*'
|
||||||
test:
|
test:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.14.6
|
- image: circleci/golang:1.15.2
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
command: go test ./...
|
command: go test ./...
|
||||||
build-go:
|
build-go:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.14.6
|
- image: circleci/golang:1.15.2
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: '~/project'
|
at: '~/project'
|
||||||
@@ -49,12 +49,12 @@ jobs:
|
|||||||
- '*'
|
- '*'
|
||||||
release:
|
release:
|
||||||
docker:
|
docker:
|
||||||
- image: circleci/golang:1.14.6
|
- image: circleci/golang:1.15.2
|
||||||
steps:
|
steps:
|
||||||
- attach_workspace:
|
- attach_workspace:
|
||||||
at: '~/project'
|
at: '~/project'
|
||||||
- setup_remote_docker
|
- setup_remote_docker
|
||||||
- run: docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
|
- run: echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin
|
||||||
- run: curl -sL https://git.io/goreleaser | bash
|
- run: curl -sL https://git.io/goreleaser | bash
|
||||||
- run: docker logout
|
- run: docker logout
|
||||||
workflows:
|
workflows:
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -2,6 +2,18 @@
|
|||||||
|
|
||||||
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.7.0](https://github.com/filebrowser/filebrowser/compare/v2.6.2...v2.7.0) (2020-09-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add --socket-perm flag to control unix socket file permissions (closes [#1060](https://github.com/filebrowser/filebrowser/issues/1060)) ([65ac734](https://github.com/filebrowser/filebrowser/commit/65ac73414fadc4686c94803a93ff319e8f7ce9d1))
|
||||||
|
* preview mobile dropdown ([7787344](https://github.com/filebrowser/filebrowser/commit/778734419de314d4cb64d07109bbab73f8e2e42a))
|
||||||
|
* preview size button ([3d2cb83](https://github.com/filebrowser/filebrowser/commit/3d2cb838d111ee61047599f49e76de80c821f341))
|
||||||
|
* put selected files in the root of the archive (closes [#1065](https://github.com/filebrowser/filebrowser/issues/1065)) ([8142b32](https://github.com/filebrowser/filebrowser/commit/8142b32f3865eccd3331328e0d087f805d186ed5))
|
||||||
|
|
||||||
|
### [2.6.2](https://github.com/filebrowser/filebrowser/compare/v2.6.1...v2.6.2) (2020-08-05)
|
||||||
|
|
||||||
### [2.6.1](https://github.com/filebrowser/filebrowser/compare/v2.6.0...v2.6.1) (2020-07-28)
|
### [2.6.1](https://github.com/filebrowser/filebrowser/compare/v2.6.0...v2.6.1) (2020-07-28)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ 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.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")
|
||||||
@@ -143,6 +144,10 @@ user created with the credentials from options "username" and "password".`,
|
|||||||
case server.Socket != "":
|
case server.Socket != "":
|
||||||
listener, err = net.Listen("unix", server.Socket)
|
listener, err = net.Listen("unix", server.Socket)
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet
|
||||||
|
checkErr(err)
|
||||||
|
err = os.Chmod(server.Socket, os.FileMode(socketPerm))
|
||||||
|
checkErr(err)
|
||||||
case server.TLSKey != "" && server.TLSCert != "":
|
case server.TLSKey != "" && server.TLSCert != "":
|
||||||
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:shadow
|
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:shadow
|
||||||
checkErr(err)
|
checkErr(err)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package fileutils
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
@@ -50,3 +51,59 @@ func CopyFile(fs afero.Fs, source, dest string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CommonPrefix returns common directory path of provided files
|
||||||
|
func CommonPrefix(sep byte, paths ...string) string {
|
||||||
|
// Handle special cases.
|
||||||
|
switch len(paths) {
|
||||||
|
case 0:
|
||||||
|
return ""
|
||||||
|
case 1:
|
||||||
|
return path.Clean(paths[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note, we treat string as []byte, not []rune as is often
|
||||||
|
// done in Go. (And sep as byte, not rune). This is because
|
||||||
|
// most/all supported OS' treat paths as string of non-zero
|
||||||
|
// bytes. A filename may be displayed as a sequence of Unicode
|
||||||
|
// runes (typically encoded as UTF-8) but paths are
|
||||||
|
// not required to be valid UTF-8 or in any normalized form
|
||||||
|
// (e.g. "é" (U+00C9) and "é" (U+0065,U+0301) are different
|
||||||
|
// file names.
|
||||||
|
c := []byte(path.Clean(paths[0]))
|
||||||
|
|
||||||
|
// We add a trailing sep to handle the case where the
|
||||||
|
// common prefix directory is included in the path list
|
||||||
|
// (e.g. /home/user1, /home/user1/foo, /home/user1/bar).
|
||||||
|
// path.Clean will have cleaned off trailing / separators with
|
||||||
|
// the exception of the root directory, "/" (in which case we
|
||||||
|
// make it "//", but this will get fixed up to "/" bellow).
|
||||||
|
c = append(c, sep)
|
||||||
|
|
||||||
|
// Ignore the first path since it's already in c
|
||||||
|
for _, v := range paths[1:] {
|
||||||
|
// Clean up each path before testing it
|
||||||
|
v = path.Clean(v) + string(sep)
|
||||||
|
|
||||||
|
// Find the first non-common byte and truncate c
|
||||||
|
if len(v) < len(c) {
|
||||||
|
c = c[:len(v)]
|
||||||
|
}
|
||||||
|
for i := 0; i < len(c); i++ {
|
||||||
|
if v[i] != c[i] {
|
||||||
|
c = c[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing non-separator characters and the final separator
|
||||||
|
for i := len(c) - 1; i >= 0; i-- {
|
||||||
|
if c[i] == sep {
|
||||||
|
c = c[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(c)
|
||||||
|
}
|
||||||
|
|||||||
46
fileutils/file_test.go
Normal file
46
fileutils/file_test.go
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package fileutils
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestCommonPrefix(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
paths []string
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
"same lvl": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/file1",
|
||||||
|
"/home/user/file2",
|
||||||
|
},
|
||||||
|
want: "/home/user",
|
||||||
|
},
|
||||||
|
"sub folder": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/folder",
|
||||||
|
"/home/user/folder/file",
|
||||||
|
},
|
||||||
|
want: "/home/user/folder",
|
||||||
|
},
|
||||||
|
"relative path": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/folder",
|
||||||
|
"/home/user/folder/../folder2",
|
||||||
|
},
|
||||||
|
want: "/home/user",
|
||||||
|
},
|
||||||
|
"no common path": {
|
||||||
|
paths: []string{
|
||||||
|
"/home/user/folder",
|
||||||
|
"/etc/file",
|
||||||
|
},
|
||||||
|
want: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tt := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
if got := CommonPrefix('/', tt.paths...); got != tt.want {
|
||||||
|
t.Errorf("CommonPrefix() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,18 +13,19 @@
|
|||||||
|
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="[{[ .StaticURL ]}]/img/icons/favicon-32x32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="[{[ .StaticURL ]}]/img/icons/favicon-32x32.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="[{[ .StaticURL ]}]/img/icons/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="[{[ .StaticURL ]}]/img/icons/favicon-16x16.png">
|
||||||
|
|
||||||
<!-- Add to home screen for Android and modern mobile browsers -->
|
<!-- Add to home screen for Android and modern mobile browsers -->
|
||||||
<link rel="manifest" id="manifestPlaceholder" crossorigin="use-credentials">
|
<link rel="manifest" id="manifestPlaceholder" crossorigin="use-credentials">
|
||||||
<meta name="theme-color" content="#2979ff">
|
<meta name="theme-color" content="#2979ff">
|
||||||
|
|
||||||
<!-- Add to home screen for Safari on iOS -->
|
<!-- Add to home screen for Safari on iOS/iPadOS -->
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-title" content="assets">
|
<meta name="apple-mobile-web-app-title" content="assets">
|
||||||
<link rel="apple-touch-icon" href="[{[ .StaticURL ]}]/img/icons/apple-touch-icon-152x152.png">
|
<link rel="apple-touch-icon" href="[{[ .StaticURL ]}]/img/icons/apple-touch-icon.png">
|
||||||
|
|
||||||
<!-- Add to home screen for Windows -->
|
<!-- Add to home screen for Windows -->
|
||||||
<meta name="msapplication-TileImage" content="[{[ .StaticURL ]}]/img/icons/msapplication-icon-144x144.png">
|
<meta name="msapplication-TileImage" content="[{[ .StaticURL ]}]/img/icons/mstile-144x144.png">
|
||||||
<meta name="msapplication-TileColor" content="#2979ff">
|
<meta name="msapplication-TileColor" content="#2979ff">
|
||||||
|
|
||||||
<!-- Inject Some Variables and generate the manifest json -->
|
<!-- Inject Some Variables and generate the manifest json -->
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<header v-if="!isEditor">
|
<header v-if="!isEditor && !isPreview">
|
||||||
<div>
|
<div>
|
||||||
<button @click="openSidebar" :aria-label="$t('buttons.toggleSidebar')" :title="$t('buttons.toggleSidebar')" class="action">
|
<button @click="openSidebar" :aria-label="$t('buttons.toggleSidebar')" :title="$t('buttons.toggleSidebar')" class="action">
|
||||||
<i class="material-icons">menu</i>
|
<i class="material-icons">menu</i>
|
||||||
@@ -108,6 +108,7 @@ export default {
|
|||||||
'selectedCount',
|
'selectedCount',
|
||||||
'isFiles',
|
'isFiles',
|
||||||
'isEditor',
|
'isEditor',
|
||||||
|
'isPreview',
|
||||||
'isListing',
|
'isListing',
|
||||||
'isLogged'
|
'isLogged'
|
||||||
]),
|
]),
|
||||||
|
|||||||
22
frontend/src/components/buttons/PreviewSize.vue
Normal file
22
frontend/src/components/buttons/PreviewSize.vue
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<button :title="$t('buttons.info')" :aria-label="$t('buttons.info')" class="action" @click="$emit('change-size')">
|
||||||
|
<i class="material-icons">{{ this.icon }}</i>
|
||||||
|
<span>{{ $t('buttons.info') }}</span>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'preview-size-button',
|
||||||
|
props: [ 'size' ],
|
||||||
|
computed: {
|
||||||
|
icon () {
|
||||||
|
if (this.size) {
|
||||||
|
return 'photo_size_select_large'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'hd'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -77,6 +77,13 @@ export default {
|
|||||||
window.removeEventListener('resize', this.onResize)
|
window.removeEventListener('resize', this.onResize)
|
||||||
document.removeEventListener('mouseup', this.onMouseUp)
|
document.removeEventListener('mouseup', this.onMouseUp)
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
src: function () {
|
||||||
|
this.scale = 1
|
||||||
|
this.setZoom()
|
||||||
|
this.setCenter()
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onLoad() {
|
onLoad() {
|
||||||
let img = this.$refs.imgex
|
let img = this.$refs.imgex
|
||||||
|
|||||||
@@ -9,10 +9,17 @@
|
|||||||
<span>{{ this.name }}</span>
|
<span>{{ this.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<rename-button :disabled="loading" v-if="user.perm.rename"></rename-button>
|
<preview-size-button v-if="isResizeEnabled && this.req.type === 'image'" @change-size="toggleSize" v-bind:size="fullSize" :disabled="loading"></preview-size-button>
|
||||||
<delete-button :disabled="loading" v-if="user.perm.delete"></delete-button>
|
<button @click="openMore" id="more" :aria-label="$t('buttons.more')" :title="$t('buttons.more')" class="action">
|
||||||
<download-button :disabled="loading" v-if="user.perm.download"></download-button>
|
<i class="material-icons">more_vert</i>
|
||||||
<info-button :disabled="loading"></info-button>
|
</button>
|
||||||
|
|
||||||
|
<div id="dropdown" :class="{ active : showMore }">
|
||||||
|
<rename-button :disabled="loading" v-if="user.perm.rename"></rename-button>
|
||||||
|
<delete-button :disabled="loading" v-if="user.perm.delete"></delete-button>
|
||||||
|
<download-button :disabled="loading" v-if="user.perm.download"></download-button>
|
||||||
|
<info-button :disabled="loading"></info-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="loading" v-if="loading">
|
<div class="loading" v-if="loading">
|
||||||
@@ -51,14 +58,17 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<div v-show="showMore" @click="resetPrompts" class="overlay"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import url from '@/utils/url'
|
import url from '@/utils/url'
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL, resizePreview } from '@/utils/constants'
|
||||||
import { files as api } from '@/api'
|
import { files as api } from '@/api'
|
||||||
|
import PreviewSizeButton from '@/components/buttons/PreviewSize'
|
||||||
import InfoButton from '@/components/buttons/Info'
|
import InfoButton from '@/components/buttons/Info'
|
||||||
import DeleteButton from '@/components/buttons/Delete'
|
import DeleteButton from '@/components/buttons/Delete'
|
||||||
import RenameButton from '@/components/buttons/Rename'
|
import RenameButton from '@/components/buttons/Rename'
|
||||||
@@ -75,6 +85,7 @@ const mediaTypes = [
|
|||||||
export default {
|
export default {
|
||||||
name: 'preview',
|
name: 'preview',
|
||||||
components: {
|
components: {
|
||||||
|
PreviewSizeButton,
|
||||||
InfoButton,
|
InfoButton,
|
||||||
DeleteButton,
|
DeleteButton,
|
||||||
RenameButton,
|
RenameButton,
|
||||||
@@ -87,7 +98,8 @@ export default {
|
|||||||
nextLink: '',
|
nextLink: '',
|
||||||
listing: null,
|
listing: null,
|
||||||
name: '',
|
name: '',
|
||||||
subtitles: []
|
subtitles: [],
|
||||||
|
fullSize: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -99,16 +111,22 @@ export default {
|
|||||||
return (this.nextLink !== '')
|
return (this.nextLink !== '')
|
||||||
},
|
},
|
||||||
download () {
|
download () {
|
||||||
return `${baseURL}/api/raw${escape(this.req.path)}?auth=${this.jwt}`
|
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${this.jwt}`
|
||||||
},
|
},
|
||||||
previewUrl () {
|
previewUrl () {
|
||||||
if (this.req.type === 'image') {
|
if (this.req.type === 'image' && !this.fullSize) {
|
||||||
return `${baseURL}/api/preview/big${escape(this.req.path)}?auth=${this.jwt}`
|
return `${baseURL}/api/preview/big${url.encodePath(this.req.path)}?auth=${this.jwt}`
|
||||||
}
|
}
|
||||||
return `${baseURL}/api/raw${escape(this.req.path)}?auth=${this.jwt}`
|
return `${baseURL}/api/raw${url.encodePath(this.req.path)}?auth=${this.jwt}`
|
||||||
},
|
},
|
||||||
raw () {
|
raw () {
|
||||||
return `${this.previewUrl}&inline=true`
|
return `${this.previewUrl}&inline=true`
|
||||||
|
},
|
||||||
|
showMore () {
|
||||||
|
return this.$store.state.show === 'more'
|
||||||
|
},
|
||||||
|
isResizeEnabled () {
|
||||||
|
return resizePreview
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -189,6 +207,15 @@ export default {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
openMore () {
|
||||||
|
this.$store.commit('showHover', 'more')
|
||||||
|
},
|
||||||
|
resetPrompts () {
|
||||||
|
this.$store.commit('closeHovers')
|
||||||
|
},
|
||||||
|
toggleSize () {
|
||||||
|
this.fullSize = !this.fullSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"home": "Accueil",
|
"home": "Accueil",
|
||||||
"lastModified": "Dernière modification",
|
"lastModified": "Dernière modification",
|
||||||
"loading": "Chargement...",
|
"loading": "Chargement...",
|
||||||
"lonely": "Il semble qu'il n'y ai rien par ici...",
|
"lonely": "Il semble qu'il n'y ait rien par ici...",
|
||||||
"metadata": "Metadonnées",
|
"metadata": "Metadonnées",
|
||||||
"multipleSelectionEnabled": "Sélection multiple activée",
|
"multipleSelectionEnabled": "Sélection multiple activée",
|
||||||
"name": "Nom",
|
"name": "Nom",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const getters = {
|
|||||||
isFiles: state => !state.loading && state.route.name === 'Files',
|
isFiles: state => !state.loading && state.route.name === 'Files',
|
||||||
isListing: (state, getters) => getters.isFiles && state.req.isDir,
|
isListing: (state, getters) => getters.isFiles && state.req.isDir,
|
||||||
isEditor: (state, getters) => getters.isFiles && (state.req.type === 'text' || state.req.type === 'textImmutable'),
|
isEditor: (state, getters) => getters.isFiles && (state.req.type === 'text' || state.req.type === 'textImmutable'),
|
||||||
|
isPreview: state => state.previewMode,
|
||||||
selectedCount: state => state.selected.length,
|
selectedCount: state => state.selected.length,
|
||||||
progress : state => {
|
progress : state => {
|
||||||
if (state.upload.progress.length == 0) {
|
if (state.upload.progress.length == 0) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const authMethod = window.FileBrowser.AuthMethod
|
|||||||
const loginPage = window.FileBrowser.LoginPage
|
const loginPage = window.FileBrowser.LoginPage
|
||||||
const theme = window.FileBrowser.Theme
|
const theme = window.FileBrowser.Theme
|
||||||
const enableThumbs = window.FileBrowser.EnableThumbs
|
const enableThumbs = window.FileBrowser.EnableThumbs
|
||||||
|
const resizePreview = window.FileBrowser.ResizePreview
|
||||||
|
|
||||||
export {
|
export {
|
||||||
name,
|
name,
|
||||||
@@ -26,5 +27,6 @@ export {
|
|||||||
authMethod,
|
authMethod,
|
||||||
loginPage,
|
loginPage,
|
||||||
theme,
|
theme,
|
||||||
enableThumbs
|
enableThumbs,
|
||||||
|
resizePreview
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ function encodeRFC5987ValueChars(str) {
|
|||||||
replace(/%(?:7C|60|5E)/g, unescape);
|
replace(/%(?:7C|60|5E)/g, unescape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function encodePath(str) {
|
||||||
|
return str.split('/').map(v => encodeURIComponent(v)).join('/')
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
encodeRFC5987ValueChars: encodeRFC5987ValueChars,
|
encodeRFC5987ValueChars: encodeRFC5987ValueChars,
|
||||||
removeLastDir: removeLastDir
|
removeLastDir: removeLastDir,
|
||||||
|
encodePath: encodePath
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
|
|||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "cty")
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
if _, err := w.Write([]byte(signed)); err != nil {
|
if _, err := w.Write([]byte(signed)); err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|||||||
13
http/raw.go
13
http/raw.go
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/mholt/archiver"
|
"github.com/mholt/archiver"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/files"
|
"github.com/filebrowser/filebrowser/v2/files"
|
||||||
|
"github.com/filebrowser/filebrowser/v2/fileutils"
|
||||||
"github.com/filebrowser/filebrowser/v2/users"
|
"github.com/filebrowser/filebrowser/v2/users"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ var rawHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data)
|
|||||||
return rawDirHandler(w, r, d, file)
|
return rawDirHandler(w, r, d, file)
|
||||||
})
|
})
|
||||||
|
|
||||||
func addFile(ar archiver.Writer, d *data, path string) error {
|
func addFile(ar archiver.Writer, d *data, path, commonPath string) error {
|
||||||
// Checks are always done with paths with "/" as path separator.
|
// Checks are always done with paths with "/" as path separator.
|
||||||
path = strings.Replace(path, "\\", "/", -1)
|
path = strings.Replace(path, "\\", "/", -1)
|
||||||
if !d.Check(path) {
|
if !d.Check(path) {
|
||||||
@@ -115,10 +116,12 @@ func addFile(ar archiver.Writer, d *data, path string) error {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
filename := strings.TrimPrefix(path, commonPath)
|
||||||
|
filename = strings.TrimPrefix(filename, "/")
|
||||||
err = ar.Write(archiver.File{
|
err = ar.Write(archiver.File{
|
||||||
FileInfo: archiver.FileInfo{
|
FileInfo: archiver.FileInfo{
|
||||||
FileInfo: info,
|
FileInfo: info,
|
||||||
CustomName: strings.TrimPrefix(path, "/"),
|
CustomName: filename,
|
||||||
},
|
},
|
||||||
ReadCloser: file,
|
ReadCloser: file,
|
||||||
})
|
})
|
||||||
@@ -133,7 +136,7 @@ func addFile(ar archiver.Writer, d *data, path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
err = addFile(ar, d, filepath.Join(path, name))
|
err = addFile(ar, d, filepath.Join(path, name), commonPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -167,8 +170,10 @@ func rawDirHandler(w http.ResponseWriter, r *http.Request, d *data, file *files.
|
|||||||
}
|
}
|
||||||
defer ar.Close()
|
defer ar.Close()
|
||||||
|
|
||||||
|
commonDir := fileutils.CommonPrefix('/', filenames...)
|
||||||
|
|
||||||
for _, fname := range filenames {
|
for _, fname := range filenames {
|
||||||
err = addFile(ar, d, fname)
|
err = addFile(ar, d, fname, commonDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, box *
|
|||||||
"ReCaptcha": false,
|
"ReCaptcha": false,
|
||||||
"Theme": d.settings.Branding.Theme,
|
"Theme": d.settings.Branding.Theme,
|
||||||
"EnableThumbs": d.server.EnableThumbnails,
|
"EnableThumbs": d.server.EnableThumbnails,
|
||||||
|
"ResizePreview": d.server.ResizePreview,
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.settings.Branding.Files != "" {
|
if d.settings.Branding.Files != "" {
|
||||||
|
|||||||
Reference in New Issue
Block a user