Add shared code support to protect shared link
This commit is contained in:
parent
f3afd5cb79
commit
4a6fdb34ff
15
Dockerfile
15
Dockerfile
@ -1,15 +0,0 @@
|
|||||||
FROM alpine:latest as alpine
|
|
||||||
RUN apk --update add ca-certificates
|
|
||||||
RUN apk --update add mailcap
|
|
||||||
|
|
||||||
FROM scratch
|
|
||||||
COPY --from=alpine /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
|
||||||
COPY --from=alpine /etc/mime.types /etc/mime.types
|
|
||||||
|
|
||||||
VOLUME /srv
|
|
||||||
EXPOSE 80
|
|
||||||
|
|
||||||
COPY .docker.json /.filebrowser.json
|
|
||||||
COPY filebrowser /filebrowser
|
|
||||||
|
|
||||||
ENTRYPOINT [ "/filebrowser" ]
|
|
||||||
1
Dockerfile
Symbolic link
1
Dockerfile
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
Dockerfile.debian
|
||||||
@ -1,4 +1,5 @@
|
|||||||
FROM alpine:latest as alpine
|
FROM alpine:latest as alpine
|
||||||
|
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
|
||||||
RUN apk --update add ca-certificates
|
RUN apk --update add ca-certificates
|
||||||
RUN apk --update add mailcap
|
RUN apk --update add mailcap
|
||||||
|
|
||||||
|
|||||||
@ -47,6 +47,7 @@ func init() {
|
|||||||
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
|
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
|
||||||
flags.String("username", "admin", "username for the first user when using quick config")
|
flags.String("username", "admin", "username for the first user when using quick config")
|
||||||
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
||||||
|
flags.String("salt", "", "The salt to use when for hashing share password. Can be any value. If changed, existing password-protected shares wil stop working.") //nolint:lll
|
||||||
|
|
||||||
addServerFlags(flags)
|
addServerFlags(flags)
|
||||||
}
|
}
|
||||||
@ -250,6 +251,10 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
|||||||
_, disableExec := getParamB(flags, "disable-exec")
|
_, disableExec := getParamB(flags, "disable-exec")
|
||||||
server.EnableExec = !disableExec
|
server.EnableExec = !disableExec
|
||||||
|
|
||||||
|
if val, set := getParamB(flags, "salt"); set {
|
||||||
|
server.Salt = val
|
||||||
|
}
|
||||||
|
|
||||||
return server
|
return server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -38,6 +38,7 @@ type FileInfo struct {
|
|||||||
Subtitles []string `json:"subtitles,omitempty"`
|
Subtitles []string `json:"subtitles,omitempty"`
|
||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
Checksums map[string]string `json:"checksums,omitempty"`
|
Checksums map[string]string `json:"checksums,omitempty"`
|
||||||
|
SharedCodeToken string `json:"sharedCodeToken,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileOptions are the options when getting a file info.
|
// FileOptions are the options when getting a file info.
|
||||||
@ -47,6 +48,7 @@ type FileOptions struct {
|
|||||||
Modify bool
|
Modify bool
|
||||||
Expand bool
|
Expand bool
|
||||||
ReadHeader bool
|
ReadHeader bool
|
||||||
|
SharedCodeToken string
|
||||||
Checker rules.Checker
|
Checker rules.Checker
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,6 +74,7 @@ func NewFileInfo(opts FileOptions) (*FileInfo, error) {
|
|||||||
IsDir: info.IsDir(),
|
IsDir: info.IsDir(),
|
||||||
Size: info.Size(),
|
Size: info.Size(),
|
||||||
Extension: filepath.Ext(info.Name()),
|
Extension: filepath.Ext(info.Name()),
|
||||||
|
SharedCodeToken: opts.SharedCodeToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Expand {
|
if opts.Expand {
|
||||||
|
|||||||
@ -4,8 +4,10 @@ export async function list() {
|
|||||||
return fetchJSON('/api/shares')
|
return fetchJSON('/api/shares')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getHash(hash) {
|
export async function getHash(hash, shared_code = "") {
|
||||||
return fetchJSON(`/api/public/share/${hash}`)
|
return fetchJSON(`/api/public/share/${hash}`, {
|
||||||
|
headers: { 'X-SHARED-CODE': shared_code },
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(url) {
|
export async function get(url) {
|
||||||
@ -23,14 +25,24 @@ export async function remove(hash) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create(url, expires = '', unit = 'hours') {
|
export async function create(url, shared_code = '', expires = '', unit = 'hours') {
|
||||||
url = removePrefix(url)
|
url = removePrefix(url)
|
||||||
url = `/api/share${url}`
|
url = `/api/share${url}`
|
||||||
|
if (shared_code !== '' || expires !== '') {
|
||||||
|
url += '?'
|
||||||
|
var params = ''
|
||||||
if (expires !== '') {
|
if (expires !== '') {
|
||||||
url += `?expires=${expires}&unit=${unit}`
|
params += `expires=${expires}&unit=${unit}`
|
||||||
|
}
|
||||||
|
if (shared_code !== '') {
|
||||||
|
if (params != '') {
|
||||||
|
params += "&"
|
||||||
|
}
|
||||||
|
params += `shared_code=${shared_code}`
|
||||||
|
}
|
||||||
|
url += params
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetchJSON(url, {
|
return fetchJSON(url, {
|
||||||
method: 'POST'
|
method: 'POST',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,167 +1,220 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="card floating" id="share">
|
<div
|
||||||
|
class="card floating"
|
||||||
|
style="max-width: max-content; width: auto"
|
||||||
|
id="share"
|
||||||
|
>
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<h2>{{ $t('buttons.share') }}</h2>
|
<h2>{{ $t("buttons.share") }}</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-if="!hasPermanent">
|
|
||||||
<a @click="getPermalink" :aria-label="$t('buttons.permalink')">{{ $t('buttons.permalink') }}</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li v-for="link in links" :key="link.hash">
|
<li v-for="link in links" :key="link.hash">
|
||||||
<a :href="buildLink(link.hash)" target="_blank">
|
<a :href="buildLink(link.hash)" target="_blank">
|
||||||
<template v-if="link.expire !== 0">{{ humanTime(link.expire) }}</template>
|
<template v-if="link.expire !== 0">{{
|
||||||
<template v-else>{{ $t('permanent') }}</template>
|
humanTime(link.expire)
|
||||||
|
}}</template>
|
||||||
|
<template v-else>{{ $t("permanent") }}</template>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<button class="action"
|
<button
|
||||||
|
class="action"
|
||||||
@click="deleteLink($event, link)"
|
@click="deleteLink($event, link)"
|
||||||
:aria-label="$t('buttons.delete')"
|
:aria-label="$t('buttons.delete')"
|
||||||
:title="$t('buttons.delete')"><i class="material-icons">delete</i></button>
|
:title="$t('buttons.delete')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button class="action copy-clipboard"
|
<button
|
||||||
:data-clipboard-text="buildLink(link.hash)"
|
class="action copy-clipboard"
|
||||||
|
:data-clipboard-text="
|
||||||
|
$t(downloadPromptsWithSharedCode(link.shared_code), [
|
||||||
|
buildLink(link.hash),
|
||||||
|
link.shared_code,
|
||||||
|
])
|
||||||
|
"
|
||||||
:aria-label="$t('buttons.copyToClipboard')"
|
:aria-label="$t('buttons.copyToClipboard')"
|
||||||
:title="$t('buttons.copyToClipboard')"><i class="material-icons">content_paste</i></button>
|
:title="$t('buttons.copyToClipboard')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">content_paste</i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li v-if="!hasPermanent">
|
||||||
|
<div style="text-align: right">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('buttons.optionalSharedCode')"
|
||||||
|
v-model="shared_code_permalink"
|
||||||
|
/>
|
||||||
|
<a @click="getPermalink" :aria-label="$t('buttons.permalink')">{{
|
||||||
|
$t("buttons.permalink")
|
||||||
|
}}</a>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<input v-focus
|
<input
|
||||||
|
v-focus
|
||||||
type="number"
|
type="number"
|
||||||
max="2147483647"
|
max="2147483647"
|
||||||
min="0"
|
min="0"
|
||||||
@keyup.enter="submit"
|
@keyup.enter="submit"
|
||||||
v-model.trim="time">
|
v-model.trim="time"
|
||||||
|
/>
|
||||||
<select v-model="unit" :aria-label="$t('time.unit')">
|
<select v-model="unit" :aria-label="$t('time.unit')">
|
||||||
<option value="seconds">{{ $t('time.seconds') }}</option>
|
<option value="seconds">{{ $t("time.seconds") }}</option>
|
||||||
<option value="minutes">{{ $t('time.minutes') }}</option>
|
<option value="minutes">{{ $t("time.minutes") }}</option>
|
||||||
<option value="hours">{{ $t('time.hours') }}</option>
|
<option value="hours">{{ $t("time.hours") }}</option>
|
||||||
<option value="days">{{ $t('time.days') }}</option>
|
<option value="days">{{ $t("time.days") }}</option>
|
||||||
</select>
|
</select>
|
||||||
<button class="action"
|
<input
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('buttons.optionalSharedCode')"
|
||||||
|
v-model="shared_code"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="action"
|
||||||
@click="submit"
|
@click="submit"
|
||||||
:aria-label="$t('buttons.create')"
|
:aria-label="$t('buttons.create')"
|
||||||
:title="$t('buttons.create')"><i class="material-icons">add</i></button>
|
:title="$t('buttons.create')"
|
||||||
|
>
|
||||||
|
<i class="material-icons">add</i>
|
||||||
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
<button class="button button--flat"
|
<button
|
||||||
|
class="button button--flat"
|
||||||
@click="$store.commit('closeHovers')"
|
@click="$store.commit('closeHovers')"
|
||||||
:aria-label="$t('buttons.close')"
|
:aria-label="$t('buttons.close')"
|
||||||
:title="$t('buttons.close')">{{ $t('buttons.close') }}</button>
|
:title="$t('buttons.close')"
|
||||||
|
>
|
||||||
|
{{ $t("buttons.close") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapGetters } from 'vuex'
|
import { mapState, mapGetters } from "vuex";
|
||||||
import { share as api } from '@/api'
|
import { share as api } from "@/api";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
import moment from 'moment'
|
import moment from "moment";
|
||||||
import Clipboard from 'clipboard'
|
import Clipboard from "clipboard";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'share',
|
name: "share",
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
time: '',
|
time: "",
|
||||||
unit: 'hours',
|
unit: "hours",
|
||||||
hasPermanent: false,
|
hasPermanent: false,
|
||||||
links: [],
|
links: [],
|
||||||
clip: null
|
clip: null,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([ 'req', 'selected', 'selectedCount' ]),
|
...mapState(["req", "selected", "selectedCount"]),
|
||||||
...mapGetters([ 'isListing' ]),
|
...mapGetters(["isListing"]),
|
||||||
url() {
|
url() {
|
||||||
if (!this.isListing) {
|
if (!this.isListing) {
|
||||||
return this.$route.path
|
return this.$route.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
if (this.selectedCount === 0 || this.selectedCount > 1) {
|
||||||
// This shouldn't happen.
|
// This shouldn't happen.
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.req.items[this.selected[0]].url
|
return this.req.items[this.selected[0]].url;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
async beforeMount() {
|
async beforeMount() {
|
||||||
try {
|
try {
|
||||||
const links = await api.get(this.url)
|
const links = await api.get(this.url);
|
||||||
this.links = links
|
this.links = links;
|
||||||
this.sort()
|
this.sort();
|
||||||
|
|
||||||
for (let link of this.links) {
|
for (let link of this.links) {
|
||||||
if (link.expire === 0) {
|
if (link.expire === 0) {
|
||||||
this.hasPermanent = true
|
this.hasPermanent = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.clip = new Clipboard('.copy-clipboard')
|
this.clip = new Clipboard(".copy-clipboard");
|
||||||
this.clip.on('success', () => {
|
this.clip.on("success", () => {
|
||||||
this.$showSuccess(this.$t('success.linkCopied'))
|
this.$showSuccess(this.$t("success.linkCopied"));
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.clip.destroy()
|
this.clip.destroy();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submit: async function () {
|
submit: async function () {
|
||||||
if (!this.time) return
|
if (!this.time) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await api.create(this.url, this.time, this.unit)
|
const res = await api.create(
|
||||||
this.links.push(res)
|
this.url,
|
||||||
this.sort()
|
this.shared_code,
|
||||||
|
this.time,
|
||||||
|
this.unit
|
||||||
|
);
|
||||||
|
this.links.push(res);
|
||||||
|
this.sort();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getPermalink: async function () {
|
getPermalink: async function () {
|
||||||
try {
|
try {
|
||||||
const res = await api.create(this.url)
|
const res = await api.create(this.url, this.shared_code_permalink);
|
||||||
this.links.push(res)
|
this.links.push(res);
|
||||||
this.sort()
|
this.sort();
|
||||||
this.hasPermanent = true
|
this.hasPermanent = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
deleteLink: async function (event, link) {
|
deleteLink: async function (event, link) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
try {
|
try {
|
||||||
await api.remove(link.hash)
|
await api.remove(link.hash);
|
||||||
if (link.expire === 0) this.hasPermanent = false
|
if (link.expire === 0) this.hasPermanent = false;
|
||||||
this.links = this.links.filter(item => item.hash !== link.hash)
|
this.links = this.links.filter((item) => item.hash !== link.hash);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.$showError(e)
|
this.$showError(e);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
humanTime(time) {
|
humanTime(time) {
|
||||||
return moment(time * 1000).fromNow()
|
return moment(time * 1000).fromNow();
|
||||||
},
|
},
|
||||||
buildLink(hash) {
|
buildLink(hash) {
|
||||||
return `${window.location.origin}${baseURL}/share/${hash}`
|
return `${window.location.origin}${baseURL}/share/${hash}`;
|
||||||
|
},
|
||||||
|
downloadPromptsWithSharedCode(shared_code) {
|
||||||
|
return shared_code != undefined && shared_code != ""
|
||||||
|
? "prompts.downloadPromptsWithSharedCode"
|
||||||
|
: "prompts.downloadPrompts";
|
||||||
},
|
},
|
||||||
sort() {
|
sort() {
|
||||||
this.links = this.links.sort((a, b) => {
|
this.links = this.links.sort((a, b) => {
|
||||||
if (a.expire === 0) return -1
|
if (a.expire === 0) return -1;
|
||||||
if (b.expire === 0) return 1
|
if (b.expire === 0) return 1;
|
||||||
return new Date(a.expire) - new Date(b.expire)
|
return new Date(a.expire) - new Date(b.expire);
|
||||||
})
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -63,3 +63,11 @@
|
|||||||
.share__box__items #listing.list .item .modified {
|
.share__box__items #listing.list .item .modified {
|
||||||
width: 25%;
|
width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.share_wrong {
|
||||||
|
background: var(--red);
|
||||||
|
color: #fff;
|
||||||
|
padding: .5em;
|
||||||
|
text-align: center;
|
||||||
|
animation: .2s opac forwards;
|
||||||
|
}
|
||||||
@ -19,6 +19,7 @@
|
|||||||
"permalink": "Get Permanent Link",
|
"permalink": "Get Permanent Link",
|
||||||
"previous": "Previous",
|
"previous": "Previous",
|
||||||
"publish": "Publish",
|
"publish": "Publish",
|
||||||
|
"password": "Password",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
"replace": "Replace",
|
"replace": "Replace",
|
||||||
"reportIssue": "Report Issue",
|
"reportIssue": "Report Issue",
|
||||||
@ -29,10 +30,13 @@
|
|||||||
"selectMultiple": "Select multiple",
|
"selectMultiple": "Select multiple",
|
||||||
"share": "Share",
|
"share": "Share",
|
||||||
"shell": "Toggle shell",
|
"shell": "Toggle shell",
|
||||||
|
"submit": "Submit",
|
||||||
"switchView": "Switch view",
|
"switchView": "Switch view",
|
||||||
"toggleSidebar": "Toggle sidebar",
|
"toggleSidebar": "Toggle sidebar",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"upload": "Upload"
|
"upload": "Upload",
|
||||||
|
"sharedCode": "Shared code",
|
||||||
|
"optionalSharedCode": "Shared code(optional)"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"downloadFile": "Download File",
|
"downloadFile": "Download File",
|
||||||
@ -142,7 +146,10 @@
|
|||||||
"show": "Show",
|
"show": "Show",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"uploadMessage": "Select an option to upload."
|
"uploadMessage": "Select an option to upload.",
|
||||||
|
"downloadPrompts": "Download url: {0}",
|
||||||
|
"downloadPromptsWithSharedCode": "Download url: {0} Shared code: {1}",
|
||||||
|
"invalidSharedCode": "Invalid shared code."
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"images": "Images",
|
"images": "Images",
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"more": "更多",
|
"more": "更多",
|
||||||
"move": "移动",
|
"move": "移动",
|
||||||
"moveFile": "移动文件",
|
"moveFile": "移动文件",
|
||||||
"new": "新",
|
"new": "新建",
|
||||||
"next": "下一个",
|
"next": "下一个",
|
||||||
"ok": "确定",
|
"ok": "确定",
|
||||||
"permalink": "获取永久链接",
|
"permalink": "获取永久链接",
|
||||||
@ -32,7 +32,9 @@
|
|||||||
"switchView": "切换显示方式",
|
"switchView": "切换显示方式",
|
||||||
"toggleSidebar": "切换侧边栏",
|
"toggleSidebar": "切换侧边栏",
|
||||||
"update": "更新",
|
"update": "更新",
|
||||||
"upload": "上传"
|
"upload": "上传",
|
||||||
|
"sharedCode": "提取码",
|
||||||
|
"optionalSharedCode": "提取码(可选)"
|
||||||
},
|
},
|
||||||
"download": {
|
"download": {
|
||||||
"downloadFile": "下载文件",
|
"downloadFile": "下载文件",
|
||||||
@ -142,7 +144,10 @@
|
|||||||
"show": "点击以显示",
|
"show": "点击以显示",
|
||||||
"size": "大小",
|
"size": "大小",
|
||||||
"upload": "上传",
|
"upload": "上传",
|
||||||
"uploadMessage": "选择上传项。"
|
"uploadMessage": "选择上传项。",
|
||||||
|
"downloadPrompts": "下载链接:{0}",
|
||||||
|
"downloadPromptsWithSharedCode": "下载链接:{0} 提取码:{1}",
|
||||||
|
"invalidSharedCode": "提取码无效!"
|
||||||
},
|
},
|
||||||
"search": {
|
"search": {
|
||||||
"images": "图像",
|
"images": "图像",
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { sync } from 'vuex-router-sync'
|
|||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import router from '@/router'
|
import router from '@/router'
|
||||||
import i18n from '@/i18n'
|
import i18n from '@/i18n'
|
||||||
import Vue from '@/utils/vue'
|
import Vue from 'vue'
|
||||||
import { recaptcha, loginPage } from '@/utils/constants'
|
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'
|
||||||
|
|||||||
@ -1,45 +1,61 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!loading">
|
<div v-if="!loading">
|
||||||
<div id="breadcrumbs">
|
<div id="breadcrumbs">
|
||||||
<router-link :to="'/share/' + hash" :aria-label="$t('files.home')" :title="$t('files.home')">
|
<router-link
|
||||||
|
:to="'/share/' + hash"
|
||||||
|
:aria-label="$t('files.home')"
|
||||||
|
:title="$t('files.home')"
|
||||||
|
>
|
||||||
<i class="material-icons">home</i>
|
<i class="material-icons">home</i>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
<span v-for="(link, index) in breadcrumbs" :key="index">
|
<span v-for="(link, index) in breadcrumbs" :key="index">
|
||||||
<span class="chevron"><i class="material-icons">keyboard_arrow_right</i></span>
|
<span class="chevron"
|
||||||
|
><i class="material-icons">keyboard_arrow_right</i></span
|
||||||
|
>
|
||||||
<router-link :to="link.url">{{ link.name }}</router-link>
|
<router-link :to="link.url">{{ link.name }}</router-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<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">
|
||||||
{{ req.isDir ? $t('download.downloadFolder') : $t('download.downloadFile') }}
|
{{
|
||||||
|
req.isDir
|
||||||
|
? $t("download.downloadFolder")
|
||||||
|
: $t("download.downloadFile")
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="share__box__element share__box__center share__box__icon">
|
<div class="share__box__element share__box__center share__box__icon">
|
||||||
<i class="material-icons">{{ icon }}</i>
|
<i class="material-icons">{{ icon }}</i>
|
||||||
</div>
|
</div>
|
||||||
<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">
|
||||||
<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">{{ $t('buttons.download') }}</a>
|
<a target="_blank" :href="link" class="button button--flat">{{
|
||||||
|
$t("buttons.download")
|
||||||
|
}}</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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="req.isDir && req.items.length > 0" class="share__box share__box__items">
|
<div
|
||||||
|
v-if="req.isDir && req.items.length > 0"
|
||||||
|
class="share__box share__box__items"
|
||||||
|
>
|
||||||
<div class="share__box__header" v-if="req.isDir">
|
<div class="share__box__header" v-if="req.isDir">
|
||||||
{{ $t('files.files') }}
|
{{ $t("files.files") }}
|
||||||
</div>
|
</div>
|
||||||
<div id="listing" class="list">
|
<div id="listing" class="list">
|
||||||
<item v-for="(item) in req.items.slice(0, this.showLimit)"
|
<item
|
||||||
|
v-for="item in req.items.slice(0, this.showLimit)"
|
||||||
:key="base64(item.name)"
|
:key="base64(item.name)"
|
||||||
v-bind:index="item.index"
|
v-bind:index="item.index"
|
||||||
v-bind:name="item.name"
|
v-bind:name="item.name"
|
||||||
@ -47,7 +63,8 @@
|
|||||||
v-bind:url="item.url"
|
v-bind:url="item.url"
|
||||||
v-bind:modified="item.modified"
|
v-bind:modified="item.modified"
|
||||||
v-bind:type="item.type"
|
v-bind:type="item.type"
|
||||||
v-bind:size="item.size">
|
v-bind:size="item.size"
|
||||||
|
>
|
||||||
</item>
|
</item>
|
||||||
<div v-if="req.items.length > showLimit" class="item">
|
<div v-if="req.items.length > showLimit" class="item">
|
||||||
<div>
|
<div>
|
||||||
@ -55,18 +72,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="{ active: $store.state.multiple }" id="multiple-selection">
|
<div
|
||||||
<p>{{ $t('files.multipleSelectionEnabled') }}</p>
|
:class="{ active: $store.state.multiple }"
|
||||||
<div @click="$store.commit('multiple', false)" tabindex="0" role="button" :title="$t('files.clear')" :aria-label="$t('files.clear')" class="action">
|
id="multiple-selection"
|
||||||
|
>
|
||||||
|
<p>{{ $t("files.multipleSelectionEnabled") }}</p>
|
||||||
|
<div
|
||||||
|
@click="$store.commit('multiple', false)"
|
||||||
|
tabindex="0"
|
||||||
|
role="button"
|
||||||
|
:title="$t('files.clear')"
|
||||||
|
:aria-label="$t('files.clear')"
|
||||||
|
class="action"
|
||||||
|
>
|
||||||
<i class="material-icons">clear</i>
|
<i class="material-icons">clear</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="req.isDir && req.items.length === 0" class="share__box share__box__items">
|
<div
|
||||||
|
v-else-if="req.isDir && req.items.length === 0"
|
||||||
|
class="share__box share__box__items"
|
||||||
|
>
|
||||||
<h2 class="message">
|
<h2 class="message">
|
||||||
<i class="material-icons">sentiment_dissatisfied</i>
|
<i class="material-icons">sentiment_dissatisfied</i>
|
||||||
<span>{{ $t('files.lonely') }}</span>
|
<span>{{ $t("files.lonely") }}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -74,136 +104,187 @@
|
|||||||
<div v-else-if="error">
|
<div v-else-if="error">
|
||||||
<not-found v-if="error.message === '404'"></not-found>
|
<not-found v-if="error.message === '404'"></not-found>
|
||||||
<forbidden v-else-if="error.message === '403'"></forbidden>
|
<forbidden v-else-if="error.message === '403'"></forbidden>
|
||||||
|
<div v-else-if="error.message === '401'">
|
||||||
|
<div class="card floating" id="shared_code">
|
||||||
|
<div class="card-title">
|
||||||
|
<h2>{{ $t("buttons.sharedCode") }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="share_wrong" v-if="shared_code != undefined && shared_code != ''">
|
||||||
|
{{ $t("prompts.invalidSharedCode") }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-content">
|
||||||
|
<input
|
||||||
|
v-focus
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('buttons.sharedCode')"
|
||||||
|
v-model="shared_code"
|
||||||
|
@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>
|
||||||
<internal-error v-else></internal-error>
|
<internal-error v-else></internal-error>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapState, mapMutations, mapGetters} from 'vuex';
|
import { mapState, mapMutations, mapGetters } from "vuex";
|
||||||
import { share as api } from '@/api'
|
import { share as api } from "@/api";
|
||||||
import { baseURL } from '@/utils/constants'
|
import { baseURL } from "@/utils/constants";
|
||||||
import filesize from 'filesize'
|
import filesize from "filesize";
|
||||||
import moment from 'moment'
|
import moment from "moment";
|
||||||
import QrcodeVue from 'qrcode.vue'
|
import QrcodeVue from "qrcode.vue";
|
||||||
import Item from "@/components/files/ListingItem"
|
import Item from "@/components/files/ListingItem";
|
||||||
import Forbidden from './errors/403'
|
import Forbidden from "./errors/403";
|
||||||
import NotFound from './errors/404'
|
import NotFound from "./errors/404";
|
||||||
import InternalError from './errors/500'
|
import InternalError from "./errors/500";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'share',
|
name: "share",
|
||||||
components: {
|
components: {
|
||||||
Item,
|
Item,
|
||||||
Forbidden,
|
Forbidden,
|
||||||
NotFound,
|
NotFound,
|
||||||
InternalError,
|
InternalError,
|
||||||
QrcodeVue
|
QrcodeVue,
|
||||||
},
|
},
|
||||||
data: () => ({
|
data: () => ({
|
||||||
error: null,
|
error: null,
|
||||||
path: '',
|
path: "",
|
||||||
showLimit: 500
|
showLimit: 500,
|
||||||
}),
|
}),
|
||||||
watch: {
|
watch: {
|
||||||
'$route': 'fetchData'
|
$route: "fetchData",
|
||||||
},
|
},
|
||||||
created: async function () {
|
created: async function () {
|
||||||
const hash = this.$route.params.pathMatch.split('/')[0]
|
const hash = this.$route.params.pathMatch.split("/")[0];
|
||||||
this.setHash(hash)
|
this.setHash(hash);
|
||||||
await this.fetchData()
|
await this.fetchData();
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
window.addEventListener('keydown', this.keyEvent)
|
window.addEventListener("keydown", this.keyEvent);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
window.removeEventListener('keydown', this.keyEvent)
|
window.removeEventListener("keydown", this.keyEvent);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['hash', 'req', 'loading', 'multiple']),
|
...mapState(["hash", "req", "loading", "multiple"]),
|
||||||
...mapGetters(['selectedCount']),
|
...mapGetters(["selectedCount"]),
|
||||||
icon: function () {
|
icon: function () {
|
||||||
if (this.req.isDir) return 'folder'
|
if (this.req.isDir) return "folder";
|
||||||
if (this.req.type === 'image') return 'insert_photo'
|
if (this.req.type === "image") return "insert_photo";
|
||||||
if (this.req.type === 'audio') return 'volume_up'
|
if (this.req.type === "audio") return "volume_up";
|
||||||
if (this.req.type === 'video') return 'movie'
|
if (this.req.type === "video") return "movie";
|
||||||
return 'insert_drive_file'
|
return "insert_drive_file";
|
||||||
},
|
},
|
||||||
link: function () {
|
link: function () {
|
||||||
return `${baseURL}/api/public/dl/${this.hash}${this.path}`
|
return `${baseURL}/api/public/dl/${this.hash}${this.path}?shared_code_token=${this.sharedCodeToken}`;
|
||||||
},
|
},
|
||||||
fullLink: function () {
|
fullLink: function () {
|
||||||
return window.location.origin + this.link
|
return window.location.origin + this.link;
|
||||||
},
|
},
|
||||||
humanSize: function () {
|
humanSize: function () {
|
||||||
if (this.req.isDir) {
|
if (this.req.isDir) {
|
||||||
return this.req.items.length
|
return this.req.items.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filesize(this.req.size)
|
return filesize(this.req.size);
|
||||||
},
|
},
|
||||||
humanTime: function () {
|
humanTime: function () {
|
||||||
return moment(this.req.modified).fromNow()
|
return moment(this.req.modified).fromNow();
|
||||||
},
|
},
|
||||||
breadcrumbs() {
|
breadcrumbs() {
|
||||||
let parts = this.path.split('/')
|
let parts = this.path.split("/");
|
||||||
|
|
||||||
if (parts[0] === '') {
|
if (parts[0] === "") {
|
||||||
parts.shift()
|
parts.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parts[parts.length - 1] === '') {
|
if (parts[parts.length - 1] === "") {
|
||||||
parts.pop()
|
parts.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
let breadcrumbs = []
|
let breadcrumbs = [];
|
||||||
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
for (let i = 0; i < parts.length; i++) {
|
||||||
if (i === 0) {
|
if (i === 0) {
|
||||||
breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: '/share/' + this.hash + '/' + parts[i] + '/' })
|
breadcrumbs.push({
|
||||||
|
name: decodeURIComponent(parts[i]),
|
||||||
|
url: "/share/" + this.hash + "/" + parts[i] + "/",
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
breadcrumbs.push({ name: decodeURIComponent(parts[i]), url: breadcrumbs[i - 1].url + parts[i] + '/' })
|
breadcrumbs.push({
|
||||||
|
name: decodeURIComponent(parts[i]),
|
||||||
|
url: breadcrumbs[i - 1].url + parts[i] + "/",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (breadcrumbs.length > 3) {
|
if (breadcrumbs.length > 3) {
|
||||||
while (breadcrumbs.length !== 4) {
|
while (breadcrumbs.length !== 4) {
|
||||||
breadcrumbs.shift()
|
breadcrumbs.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
breadcrumbs[0].name = '...'
|
breadcrumbs[0].name = "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
return breadcrumbs
|
return breadcrumbs;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations([ 'setHash', 'resetSelected', 'updateRequest', 'setLoading' ]),
|
...mapMutations([
|
||||||
|
"setHash",
|
||||||
|
"resetSelected",
|
||||||
|
"updateRequest",
|
||||||
|
"setLoading",
|
||||||
|
]),
|
||||||
base64: function (name) {
|
base64: function (name) {
|
||||||
return window.btoa(unescape(encodeURIComponent(name)))
|
return window.btoa(unescape(encodeURIComponent(name)));
|
||||||
},
|
},
|
||||||
fetchData: async function () {
|
fetchData: async function () {
|
||||||
// Reset view information.
|
// Reset view information.
|
||||||
this.$store.commit('setReload', false)
|
this.$store.commit("setReload", false);
|
||||||
this.$store.commit('resetSelected')
|
this.$store.commit("resetSelected");
|
||||||
this.$store.commit('multiple', false)
|
this.$store.commit("multiple", false);
|
||||||
this.$store.commit('closeHovers')
|
this.$store.commit("closeHovers");
|
||||||
|
|
||||||
// Set loading to true and reset the error.
|
// Set loading to true and reset the error.
|
||||||
this.setLoading(true)
|
this.setLoading(true);
|
||||||
this.error = null
|
this.error = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let file = await api.getHash(encodeURIComponent(this.$route.params.pathMatch))
|
const shared_code = this.shared_code || "";
|
||||||
this.path = file.path
|
let file = await api.getHash(
|
||||||
if (file.isDir) file.items = file.items.map((item, index) => {
|
encodeURIComponent(this.$route.params.pathMatch),
|
||||||
item.index = index
|
shared_code
|
||||||
item.url = `/share/${this.hash}${this.path}/${encodeURIComponent(item.name)}`
|
);
|
||||||
return item
|
this.path = file.path;
|
||||||
})
|
this.sharedCodeToken = file.sharedCodeToken || "";
|
||||||
this.updateRequest(file)
|
if (file.isDir)
|
||||||
this.setLoading(false)
|
file.items = file.items.map((item, index) => {
|
||||||
|
item.index = index;
|
||||||
|
item.url = `/share/${this.hash}${this.path}/${encodeURIComponent(
|
||||||
|
item.name
|
||||||
|
)}`;
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
this.updateRequest(file);
|
||||||
|
this.setLoading(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.error = e
|
console.log(e);
|
||||||
|
this.error = e;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyEvent(event) {
|
keyEvent(event) {
|
||||||
@ -212,13 +293,13 @@ export default {
|
|||||||
// If we're on a listing, unselect all
|
// If we're on a listing, unselect all
|
||||||
// files and folders.
|
// files and folders.
|
||||||
if (this.selectedCount > 0) {
|
if (this.selectedCount > 0) {
|
||||||
this.resetSelected()
|
this.resetSelected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleMultipleSelection() {
|
toggleMultipleSelection() {
|
||||||
this.$store.commit('multiple', !this.multiple)
|
this.$store.commit("multiple", !this.multiple);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
7
go.mod
7
go.mod
@ -2,7 +2,7 @@ module github.com/filebrowser/filebrowser/v2
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/DataDog/zstd v1.4.0 // indirect
|
github.com/DataDog/zstd v1.4.0 // indirect
|
||||||
github.com/GeertJohan/go.rice v1.0.0
|
github.com/GeertJohan/go.rice v1.0.2
|
||||||
github.com/Sereal/Sereal v0.0.0-20190430203904-6faf9605eb56 // indirect
|
github.com/Sereal/Sereal v0.0.0-20190430203904-6faf9605eb56 // indirect
|
||||||
github.com/asdine/storm v2.1.2+incompatible
|
github.com/asdine/storm v2.1.2+incompatible
|
||||||
github.com/caddyserver/caddy v1.0.3
|
github.com/caddyserver/caddy v1.0.3
|
||||||
@ -10,6 +10,7 @@ require (
|
|||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/dsnet/compress v0.0.1 // indirect
|
github.com/dsnet/compress v0.0.1 // indirect
|
||||||
|
github.com/golang/protobuf v1.3.3 // indirect
|
||||||
github.com/golang/snappy v0.0.1 // indirect
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
github.com/gorilla/mux v1.7.3
|
github.com/gorilla/mux v1.7.3
|
||||||
github.com/gorilla/websocket v1.4.1
|
github.com/gorilla/websocket v1.4.1
|
||||||
@ -33,11 +34,11 @@ require (
|
|||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8
|
||||||
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b // indirect
|
golang.org/x/net v0.0.0-20200528225125-3c3fba18258b // indirect
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
|
||||||
golang.org/x/text v0.3.2 // indirect
|
golang.org/x/text v0.3.2 // indirect
|
||||||
google.golang.org/appengine v1.5.0 // indirect
|
google.golang.org/appengine v1.5.0 // indirect
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
gopkg.in/yaml.v2 v2.2.7
|
gopkg.in/yaml.v2 v2.2.8
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|||||||
22
go.sum
22
go.sum
@ -5,8 +5,8 @@ github.com/DataDog/zstd v1.4.0 h1:vhoV+DUHnRZdKW1i5UMjAk2G4JY8wN4ayRfYDNdEhwo=
|
|||||||
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
github.com/DataDog/zstd v1.4.0/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||||
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
|
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
|
||||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||||
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
|
github.com/GeertJohan/go.rice v1.0.2 h1:PtRw+Tg3oa3HYwiDBZyvOJ8LdIyf6lAovJJtr7YOAYk=
|
||||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
github.com/GeertJohan/go.rice v1.0.2/go.mod h1:af5vUNlDNkCjOZeSGFgIJxDje9qdjsO6hshx0gTmZt4=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/Sereal/Sereal v0.0.0-20190430203904-6faf9605eb56 h1:3trCIB5GsAOIY8NxlfMztCYIhVsW9V5sZ+brsecjaiI=
|
github.com/Sereal/Sereal v0.0.0-20190430203904-6faf9605eb56 h1:3trCIB5GsAOIY8NxlfMztCYIhVsW9V5sZ+brsecjaiI=
|
||||||
github.com/Sereal/Sereal v0.0.0-20190430203904-6faf9605eb56/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
github.com/Sereal/Sereal v0.0.0-20190430203904-6faf9605eb56/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||||
@ -33,6 +33,7 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
|
|||||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||||
github.com/daaku/go.zipexe v1.0.1 h1:wV4zMsDOI2SZ2m7Tdz1Ps96Zrx+TzaK15VbUaGozw0M=
|
github.com/daaku/go.zipexe v1.0.1 h1:wV4zMsDOI2SZ2m7Tdz1Ps96Zrx+TzaK15VbUaGozw0M=
|
||||||
@ -70,6 +71,8 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM
|
|||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||||
|
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@ -107,6 +110,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
@ -143,8 +147,8 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
|||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||||
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
|
github.com/nkovacs/streamquote v1.0.0 h1:PmVIV08Zlx2lZK5fFZlMZ04eHcDTIFJCv/5/0twVUow=
|
||||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
github.com/nkovacs/streamquote v1.0.0/go.mod h1:BN+NaZ2CmdKqUuTUXUEm9j95B2TRbpOWpxbJYzzgUsc=
|
||||||
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
|
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
|
||||||
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
@ -172,7 +176,9 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
|
|||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
@ -280,8 +286,8 @@ golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e h1:ZytStCyV048ZqDsWHiYDdoI2V
|
|||||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk=
|
||||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
@ -318,8 +324,8 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -9,6 +10,7 @@ import (
|
|||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
||||||
"github.com/filebrowser/filebrowser/v2/files"
|
"github.com/filebrowser/filebrowser/v2/files"
|
||||||
|
"github.com/filebrowser/filebrowser/v2/share"
|
||||||
)
|
)
|
||||||
|
|
||||||
var withHashFile = func(fn handleFunc) handleFunc {
|
var withHashFile = func(fn handleFunc) handleFunc {
|
||||||
@ -19,6 +21,11 @@ var withHashFile = func(fn handleFunc) handleFunc {
|
|||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status, err := authenticateShareRequest(r, link, d.server.Salt)
|
||||||
|
if err != nil {
|
||||||
|
return status, err
|
||||||
|
}
|
||||||
|
|
||||||
user, err := d.store.Users.Get(d.server.Root, link.UserID)
|
user, err := d.store.Users.Get(d.server.Root, link.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
@ -33,6 +40,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
|
|||||||
Expand: true,
|
Expand: true,
|
||||||
ReadHeader: d.server.TypeDetectionByHeader,
|
ReadHeader: d.server.TypeDetectionByHeader,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
|
SharedCodeToken: link.SharedCodeToken,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
@ -48,6 +56,7 @@ var withHashFile = func(fn handleFunc) handleFunc {
|
|||||||
Modify: d.user.Perm.Modify,
|
Modify: d.user.Perm.Modify,
|
||||||
Expand: true,
|
Expand: true,
|
||||||
Checker: d,
|
Checker: d,
|
||||||
|
SharedCodeToken: link.SharedCodeToken,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errToStatus(err), err
|
return errToStatus(err), err
|
||||||
@ -94,3 +103,20 @@ var publicDlHandler = withHashFile(func(w http.ResponseWriter, r *http.Request,
|
|||||||
|
|
||||||
return rawDirHandler(w, r, d, file)
|
return rawDirHandler(w, r, d, file)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func authenticateShareRequest(r *http.Request, l *share.Link, salt string) (int, error) {
|
||||||
|
if l.SharedCode == "" {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedCodeToken := r.URL.Query().Get("shared_code_token")
|
||||||
|
if sharedCodeToken == l.SharedCodeToken {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedCode := r.Header.Get("X-SHARED-CODE")
|
||||||
|
if l.SharedCode != sharedCode {
|
||||||
|
return http.StatusUnauthorized, errors.New("invalid shared code")
|
||||||
|
}
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -82,6 +82,10 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
|||||||
rawExpire := r.URL.Query().Get("expires")
|
rawExpire := r.URL.Query().Get("expires")
|
||||||
unit := r.URL.Query().Get("unit")
|
unit := r.URL.Query().Get("unit")
|
||||||
|
|
||||||
|
if r.Body != nil {
|
||||||
|
defer r.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
if rawExpire == "" {
|
if rawExpire == "" {
|
||||||
var err error
|
var err error
|
||||||
s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID)
|
s, err = d.store.Share.GetPermanent(r.URL.Path, d.user.ID)
|
||||||
@ -104,6 +108,7 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
|||||||
var expire int64 = 0
|
var expire int64 = 0
|
||||||
|
|
||||||
if rawExpire != "" {
|
if rawExpire != "" {
|
||||||
|
//nolint:govet
|
||||||
num, err := strconv.Atoi(rawExpire)
|
num, err := strconv.Atoi(rawExpire)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
@ -124,11 +129,30 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
|||||||
expire = time.Now().Add(add).Unix()
|
expire = time.Now().Add(add).Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sharedCode := r.URL.Query().Get("shared_code")
|
||||||
|
if sharedCode == "" {
|
||||||
s = &share.Link{
|
s = &share.Link{
|
||||||
Path: r.URL.Path,
|
Path: r.URL.Path,
|
||||||
Hash: str,
|
Hash: str,
|
||||||
Expire: expire,
|
Expire: expire,
|
||||||
UserID: d.user.ID,
|
UserID: d.user.ID,
|
||||||
|
SharedCodeToken: "",
|
||||||
|
SharedCode: "",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tokenBuffer := make([]byte, 96)
|
||||||
|
if _, err := rand.Read(tokenBuffer); err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
token := base64.URLEncoding.EncodeToString(tokenBuffer)
|
||||||
|
s = &share.Link{
|
||||||
|
Path: r.URL.Path,
|
||||||
|
Hash: str,
|
||||||
|
Expire: expire,
|
||||||
|
UserID: d.user.ID,
|
||||||
|
SharedCodeToken: token,
|
||||||
|
SharedCode: sharedCode,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := d.store.Share.Save(s); err != nil {
|
if err := d.store.Share.Save(s); err != nil {
|
||||||
|
|||||||
@ -38,6 +38,7 @@ type Server struct {
|
|||||||
Port string `json:"port"`
|
Port string `json:"port"`
|
||||||
Address string `json:"address"`
|
Address string `json:"address"`
|
||||||
Log string `json:"log"`
|
Log string `json:"log"`
|
||||||
|
Salt string `json:"salt"`
|
||||||
EnableThumbnails bool `json:"enableThumbnails"`
|
EnableThumbnails bool `json:"enableThumbnails"`
|
||||||
ResizePreview bool `json:"resizePreview"`
|
ResizePreview bool `json:"resizePreview"`
|
||||||
EnableExec bool `json:"enableExec"`
|
EnableExec bool `json:"enableExec"`
|
||||||
|
|||||||
@ -6,4 +6,6 @@ type Link struct {
|
|||||||
Path string `json:"path" storm:"index"`
|
Path string `json:"path" storm:"index"`
|
||||||
UserID uint `json:"userID"`
|
UserID uint `json:"userID"`
|
||||||
Expire int64 `json:"expire"`
|
Expire int64 `json:"expire"`
|
||||||
|
SharedCode string `json:"shared_code,omitempty"`
|
||||||
|
SharedCodeToken string `json:"token,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@ -102,9 +102,11 @@ func (s *Storage) Gets(path string, id uint) ([]*Link, error) {
|
|||||||
if err := s.Delete(link.Hash); err != nil {
|
if err := s.Delete(link.Hash); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(links) > i+1 {
|
||||||
links = append(links[:i], links[i+1:]...)
|
links = append(links[:i], links[i+1:]...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return links, nil
|
return links, nil
|
||||||
}
|
}
|
||||||
|
|||||||
17
wizard.sh
17
wizard.sh
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env sh
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@ -35,7 +35,8 @@ buildAssets () {
|
|||||||
|
|
||||||
buildBinary () {
|
buildBinary () {
|
||||||
if ! [ -x "$(command -v rice)" ]; then
|
if ! [ -x "$(command -v rice)" ]; then
|
||||||
go install github.com/GeertJohan/go.rice/rice
|
go get github.com/GeertJohan/go.rice
|
||||||
|
go get github.com/GeertJohan/go.rice/rice
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd $REPO/http
|
cd $REPO/http
|
||||||
@ -55,28 +56,24 @@ release () {
|
|||||||
echo "❌ This release script requires a single argument corresponding to the semver to be released. See semver.org"
|
echo "❌ This release script requires a single argument corresponding to the semver to be released. See semver.org"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
echo "1"
|
||||||
GREP="grep"
|
GREP="grep"
|
||||||
if [ -x "$(command -v ggrep)" ]; then
|
if [ -x "$(command -v ggrep)" ]; then
|
||||||
GREP="ggrep"
|
GREP="ggrep"
|
||||||
fi
|
fi
|
||||||
|
semver=$(echo "$1" | $GREP -P "^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)")
|
||||||
semver=$(echo "$1" | $GREP -P '^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)')
|
err=$?
|
||||||
|
if [ $err -ne 0 ]; then
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
echo "❌ Not valid semver format. See semver.org"
|
echo "❌ Not valid semver format. See semver.org"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🧼 Tidying up go modules"
|
echo "🧼 Tidying up go modules"
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
|
||||||
echo "🐑 Creating a new commit for the new release"
|
echo "🐑 Creating a new commit for the new release"
|
||||||
git commit --allow-empty -am "chore: version $semver"
|
git commit --allow-empty -am "chore: version $semver"
|
||||||
git tag "$1"
|
git tag "$1"
|
||||||
git push
|
git push
|
||||||
git push --tags origin
|
git push --tags origin
|
||||||
|
|
||||||
echo "📦 Done! $semver released."
|
echo "📦 Done! $semver released."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user