Compare commits
29 Commits
limit-cors
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdd6ff9435 | ||
|
|
29bd44ac0c | ||
|
|
4b9be2fd12 | ||
|
|
2d7a0f1aaf | ||
|
|
23f70c844a | ||
|
|
6d8af0af8f | ||
|
|
189100b3af | ||
|
|
75eb27f9c9 | ||
|
|
e31775af89 | ||
|
|
2a0e1f7400 | ||
|
|
dbd0e06c73 | ||
|
|
bd2d79953d | ||
|
|
dd8692b656 | ||
|
|
eacf2d1dc3 | ||
|
|
08e2cf764d | ||
|
|
a400a028ff | ||
|
|
f2fb06ae18 | ||
|
|
71957e4947 | ||
|
|
5fab10ed10 | ||
|
|
30e4b86595 | ||
|
|
5bcbcd0bac | ||
|
|
2a5610bb74 | ||
|
|
b86e0e623e | ||
|
|
bca7b842f5 | ||
|
|
6de7ca4676 | ||
|
|
88433ea55e | ||
|
|
d874ba59cf | ||
|
|
5dc0040375 | ||
|
|
034215a031 |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -29,6 +29,6 @@ jobs:
|
|||||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||||
distribution: goreleaser
|
distribution: goreleaser
|
||||||
version: latest
|
version: latest
|
||||||
args: release --rm-dist
|
args: release
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
version: 2
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
- go mod tidy
|
- go mod tidy
|
||||||
@@ -16,8 +17,16 @@ builds:
|
|||||||
- "386"
|
- "386"
|
||||||
goarm:
|
goarm:
|
||||||
- "6"
|
- "6"
|
||||||
brews:
|
|
||||||
- tap:
|
archives:
|
||||||
owner: codeskyblue
|
- format: tar.gz
|
||||||
name: homebrew-tap
|
# use zip for windows archives
|
||||||
folder: Formula
|
format_overrides:
|
||||||
|
- goos: windows
|
||||||
|
format: zip
|
||||||
|
|
||||||
|
# brews:
|
||||||
|
# - tap:
|
||||||
|
# owner: codeskyblue
|
||||||
|
# name: homebrew-tap
|
||||||
|
# folder: Formula
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Tested with go-1.16
|
|||||||
1. [x] Apple ipa auto generate .plist file, qrcode can be recognized by iphone (Require https)
|
1. [x] Apple ipa auto generate .plist file, qrcode can be recognized by iphone (Require https)
|
||||||
1. [x] Plist proxy
|
1. [x] Plist proxy
|
||||||
1. [ ] Download count statistics
|
1. [ ] Download count statistics
|
||||||
1. [x] CORS enabled (AllowMethods: GET, HEAD, OPTIONS)
|
1. [x] CORS enabled
|
||||||
1. [ ] Offline download
|
1. [ ] Offline download
|
||||||
1. [ ] Code file preview
|
1. [ ] Code file preview
|
||||||
1. [ ] Edit file support
|
1. [ ] Edit file support
|
||||||
@@ -91,7 +91,7 @@ Share current directory with http basic auth
|
|||||||
```bash
|
```bash
|
||||||
$ docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name gohttpserver \
|
$ docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name gohttpserver \
|
||||||
codeskyblue/gohttpserver \
|
codeskyblue/gohttpserver \
|
||||||
--auth-type http --auth-http username:password
|
--auth-type http --auth-http username1:password1 --auth-http username2:password2
|
||||||
```
|
```
|
||||||
|
|
||||||
Share current directory with openid auth. (Works only in netease company.)
|
Share current directory with openid auth. (Works only in netease company.)
|
||||||
@@ -113,7 +113,7 @@ $ docker build -t codeskyblue/gohttpserver -f docker/Dockerfile .
|
|||||||
- Enable basic http authentication
|
- Enable basic http authentication
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ gohttpserver --auth-type http --auth-http username:password
|
$ gohttpserver --auth-type http --auth-http username1:password1 --auth-http username2:password2
|
||||||
```
|
```
|
||||||
|
|
||||||
- Use openid auth
|
- Use openid auth
|
||||||
|
|||||||
@@ -64,6 +64,8 @@
|
|||||||
</template>
|
</template>
|
||||||
[[end]]
|
[[end]]
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
[[if not .NoIndex ]]
|
||||||
<form class="navbar-form navbar-right">
|
<form class="navbar-form navbar-right">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" name="search" class="form-control" placeholder="Search text" v-bind:value="search"
|
<input type="text" name="search" class="form-control" placeholder="Search text" v-bind:value="search"
|
||||||
@@ -75,6 +77,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
[[end]]
|
||||||
<ul id="nav-right-bar" class="nav navbar-nav navbar-right">
|
<ul id="nav-right-bar" class="nav navbar-nav navbar-right">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -239,7 +239,15 @@ var vm = new Vue({
|
|||||||
var reqPath = this.getEncodePath(f.name)
|
var reqPath = this.getEncodePath(f.name)
|
||||||
// TODO: fix here tomorrow
|
// TODO: fix here tomorrow
|
||||||
if (f.type == "file") {
|
if (f.type == "file") {
|
||||||
window.location.href = reqPath;
|
// check whether the file is video
|
||||||
|
var videoExtensions = ['mp4', 'webm', 'ogg', 'mov', 'avi', 'mkv'];
|
||||||
|
var fileExtension = getExtention(f.name).toLowerCase();
|
||||||
|
if (videoExtensions.includes(fileExtension)) {
|
||||||
|
window.location.href = '/-/video-player' + reqPath;
|
||||||
|
} else {
|
||||||
|
window.location.href = reqPath;
|
||||||
|
}
|
||||||
|
e.preventDefault()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loadFileOrDir(reqPath);
|
loadFileOrDir(reqPath);
|
||||||
|
|||||||
49
assets/video-player.html
Normal file
49
assets/video-player.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Video Player - [[.FileName]]</title>
|
||||||
|
<style>
|
||||||
|
body, html {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
.video-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 24px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="video-container">
|
||||||
|
<video id="videoPlayer" controls autoplay>
|
||||||
|
<source src="[[.VideoURL]]" type="video/[[.Extension]]">
|
||||||
|
Your browser does not support the video tag.
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var video = document.getElementById('videoPlayer');
|
||||||
|
video.focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -3,7 +3,7 @@ WORKDIR /app/gohttpserver
|
|||||||
ADD . /app/gohttpserver
|
ADD . /app/gohttpserver
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags '-X main.VERSION=docker' -o gohttpserver
|
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags '-X main.VERSION=docker' -o gohttpserver
|
||||||
|
|
||||||
FROM debian:stretch
|
FROM debian:stable
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
RUN mkdir -p /app/public
|
RUN mkdir -p /app/public
|
||||||
RUN apt-get update && apt-get install -y ca-certificates
|
RUN apt-get update && apt-get install -y ca-certificates
|
||||||
|
|||||||
19
docker/Dockerfile.alpine
Normal file
19
docker/Dockerfile.alpine
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
FROM golang:1.16.0-alpine as build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY go.mod .
|
||||||
|
COPY go.sum .
|
||||||
|
RUN go mod download
|
||||||
|
# Binary Compression
|
||||||
|
RUN apk add upx --no-cache
|
||||||
|
|
||||||
|
# Build app and pack using upx
|
||||||
|
ADD . /app
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags '-s -w -X main.VERSION=docker' -o gohttpserver && upx gohttpserver
|
||||||
|
|
||||||
|
FROM alpine:3
|
||||||
|
WORKDIR /app
|
||||||
|
ADD assets /usr/local/bin/assets
|
||||||
|
COPY --from=build /app/gohttpserver /usr/local/bin/gohttpserver
|
||||||
|
EXPOSE 8000
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/gohttpserver" ]
|
||||||
4
go.mod
4
go.mod
@@ -19,7 +19,7 @@ require (
|
|||||||
github.com/shogo82148/androidbinary v0.0.0-20180627093851-01c4bfa8b3b5
|
github.com/shogo82148/androidbinary v0.0.0-20180627093851-01c4bfa8b3b5
|
||||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.3.0
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
|
golang.org/x/net v0.23.0 // indirect
|
||||||
golang.org/x/text v0.3.3
|
golang.org/x/text v0.14.0
|
||||||
howett.net/plist v0.0.0-20201203080718-1454fab16a06 // indirect
|
howett.net/plist v0.0.0-20201203080718-1454fab16a06 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
47
go.sum
47
go.sum
@@ -51,20 +51,53 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
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.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -48,22 +48,24 @@ type Directory struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HTTPStaticServer struct {
|
type HTTPStaticServer struct {
|
||||||
Root string
|
Root string
|
||||||
Prefix string
|
Prefix string
|
||||||
Upload bool
|
Upload bool
|
||||||
Delete bool
|
Delete bool
|
||||||
Title string
|
Title string
|
||||||
Theme string
|
Theme string
|
||||||
PlistProxy string
|
PlistProxy string
|
||||||
GoogleTrackerID string
|
GoogleTrackerID string
|
||||||
AuthType string
|
AuthType string
|
||||||
|
DeepPathMaxDepth int
|
||||||
|
NoIndex bool
|
||||||
|
|
||||||
indexes []IndexFileItem
|
indexes []IndexFileItem
|
||||||
m *mux.Router
|
m *mux.Router
|
||||||
bufPool sync.Pool // use sync.Pool caching buf to reduce gc ratio
|
bufPool sync.Pool // use sync.Pool caching buf to reduce gc ratio
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPStaticServer(root string) *HTTPStaticServer {
|
func NewHTTPStaticServer(root string, noIndex bool) *HTTPStaticServer {
|
||||||
// if root == "" {
|
// if root == "" {
|
||||||
// root = "./"
|
// root = "./"
|
||||||
// }
|
// }
|
||||||
@@ -81,23 +83,27 @@ func NewHTTPStaticServer(root string) *HTTPStaticServer {
|
|||||||
bufPool: sync.Pool{
|
bufPool: sync.Pool{
|
||||||
New: func() interface{} { return make([]byte, 32*1024) },
|
New: func() interface{} { return make([]byte, 32*1024) },
|
||||||
},
|
},
|
||||||
|
NoIndex: noIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
if !noIndex {
|
||||||
time.Sleep(1 * time.Second)
|
go func() {
|
||||||
for {
|
time.Sleep(1 * time.Second)
|
||||||
startTime := time.Now()
|
for {
|
||||||
log.Println("Started making search index")
|
startTime := time.Now()
|
||||||
s.makeIndex()
|
log.Println("Started making search index")
|
||||||
log.Printf("Completed search index in %v", time.Since(startTime))
|
s.makeIndex()
|
||||||
//time.Sleep(time.Second * 1)
|
log.Printf("Completed search index in %v", time.Since(startTime))
|
||||||
time.Sleep(time.Minute * 10)
|
//time.Sleep(time.Second * 1)
|
||||||
}
|
time.Sleep(time.Minute * 10)
|
||||||
}()
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// routers for Apple *.ipa
|
// routers for Apple *.ipa
|
||||||
m.HandleFunc("/-/ipa/plist/{path:.*}", s.hPlist)
|
m.HandleFunc("/-/ipa/plist/{path:.*}", s.hPlist)
|
||||||
m.HandleFunc("/-/ipa/link/{path:.*}", s.hIpaLink)
|
m.HandleFunc("/-/ipa/link/{path:.*}", s.hIpaLink)
|
||||||
|
m.HandleFunc("/-/video-player/{path:.*}", s.hVideoPlayer)
|
||||||
|
|
||||||
m.HandleFunc("/{path:.*}", s.hIndex).Methods("GET", "HEAD")
|
m.HandleFunc("/{path:.*}", s.hIndex).Methods("GET", "HEAD")
|
||||||
m.HandleFunc("/{path:.*}", s.hUploadOrMkdir).Methods("POST")
|
m.HandleFunc("/{path:.*}", s.hUploadOrMkdir).Methods("POST")
|
||||||
@@ -571,6 +577,7 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
|
|||||||
auth := s.readAccessConf(realPath)
|
auth := s.readAccessConf(realPath)
|
||||||
auth.Upload = auth.canUpload(r)
|
auth.Upload = auth.canUpload(r)
|
||||||
auth.Delete = auth.canDelete(r)
|
auth.Delete = auth.canDelete(r)
|
||||||
|
maxDepth := s.DeepPathMaxDepth
|
||||||
|
|
||||||
// path string -> info os.FileInfo
|
// path string -> info os.FileInfo
|
||||||
fileInfoMap := make(map[string]os.FileInfo, 0)
|
fileInfoMap := make(map[string]os.FileInfo, 0)
|
||||||
@@ -615,7 +622,7 @@ func (s *HTTPStaticServer) hJSONList(w http.ResponseWriter, r *http.Request) {
|
|||||||
lr.Name = filepath.ToSlash(name) // fix for windows
|
lr.Name = filepath.ToSlash(name) // fix for windows
|
||||||
}
|
}
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
name := deepPath(realPath, info.Name())
|
name := deepPath(realPath, info.Name(), maxDepth)
|
||||||
lr.Name = name
|
lr.Name = name
|
||||||
lr.Path = filepath.Join(filepath.Dir(path), name)
|
lr.Path = filepath.Join(filepath.Dir(path), name)
|
||||||
lr.Type = "dir"
|
lr.Type = "dir"
|
||||||
@@ -740,9 +747,8 @@ func (s *HTTPStaticServer) readAccessConf(realPath string) (ac AccessConf) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func deepPath(basedir, name string) string {
|
func deepPath(basedir, name string, maxDepth int) string {
|
||||||
// loop max 5, incase of for loop not finished
|
// loop max 5, incase of for loop not finished
|
||||||
maxDepth := 5
|
|
||||||
for depth := 0; depth <= maxDepth; depth += 1 {
|
for depth := 0; depth <= maxDepth; depth += 1 {
|
||||||
finfos, err := ioutil.ReadDir(filepath.Join(basedir, name))
|
finfos, err := ioutil.ReadDir(filepath.Join(basedir, name))
|
||||||
if err != nil || len(finfos) != 1 {
|
if err != nil || len(finfos) != 1 {
|
||||||
@@ -811,3 +817,28 @@ func checkFilename(name string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *HTTPStaticServer) hVideoPlayer(w http.ResponseWriter, r *http.Request) {
|
||||||
|
path := mux.Vars(r)["path"]
|
||||||
|
realPath := s.getRealPath(r)
|
||||||
|
extension := strings.ToLower(strings.TrimPrefix(filepath.Ext(path), "."))
|
||||||
|
|
||||||
|
if _, err := os.Stat(realPath); os.IsNotExist(err) {
|
||||||
|
http.Error(w, "File not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := filepath.Base(path)
|
||||||
|
|
||||||
|
scheme := "http"
|
||||||
|
if r.TLS != nil {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
videoURL := fmt.Sprintf("%s://%s/%s", scheme, r.Host, path)
|
||||||
|
|
||||||
|
renderHTML(w, "assets/video-player.html", map[string]interface{}{
|
||||||
|
"FileName": fileName,
|
||||||
|
"VideoURL": videoURL,
|
||||||
|
"Extension": extension,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
71
main.go
71
main.go
@@ -2,6 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/subtle"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -33,7 +35,6 @@ type Configure struct {
|
|||||||
HTTPAuth string `yaml:"httpauth"`
|
HTTPAuth string `yaml:"httpauth"`
|
||||||
Cert string `yaml:"cert"`
|
Cert string `yaml:"cert"`
|
||||||
Key string `yaml:"key"`
|
Key string `yaml:"key"`
|
||||||
Cors bool `yaml:"cors"`
|
|
||||||
Theme string `yaml:"theme"`
|
Theme string `yaml:"theme"`
|
||||||
XHeaders bool `yaml:"xheaders"`
|
XHeaders bool `yaml:"xheaders"`
|
||||||
Upload bool `yaml:"upload"`
|
Upload bool `yaml:"upload"`
|
||||||
@@ -43,12 +44,14 @@ type Configure struct {
|
|||||||
Debug bool `yaml:"debug"`
|
Debug bool `yaml:"debug"`
|
||||||
GoogleTrackerID string `yaml:"google-tracker-id"`
|
GoogleTrackerID string `yaml:"google-tracker-id"`
|
||||||
Auth struct {
|
Auth struct {
|
||||||
Type string `yaml:"type"` // openid|http|github
|
Type string `yaml:"type"` // openid|http|github
|
||||||
OpenID string `yaml:"openid"`
|
OpenID string `yaml:"openid"`
|
||||||
HTTP string `yaml:"http"`
|
HTTP []string `yaml:"http"`
|
||||||
ID string `yaml:"id"` // for oauth2
|
ID string `yaml:"id"` // for oauth2
|
||||||
Secret string `yaml:"secret"` // for oauth2
|
Secret string `yaml:"secret"` // for oauth2
|
||||||
} `yaml:"auth"`
|
} `yaml:"auth"`
|
||||||
|
DeepPathMaxDepth int `yaml:"deep-path-max-depth"`
|
||||||
|
NoIndex bool `yaml:"no-index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type httpLogger struct{}
|
type httpLogger struct{}
|
||||||
@@ -99,6 +102,8 @@ func parseFlags() error {
|
|||||||
gcfg.Auth.OpenID = defaultOpenID
|
gcfg.Auth.OpenID = defaultOpenID
|
||||||
gcfg.GoogleTrackerID = "UA-81205425-2"
|
gcfg.GoogleTrackerID = "UA-81205425-2"
|
||||||
gcfg.Title = "Go HTTP File Server"
|
gcfg.Title = "Go HTTP File Server"
|
||||||
|
gcfg.DeepPathMaxDepth = 5
|
||||||
|
gcfg.NoIndex = false
|
||||||
|
|
||||||
kingpin.HelpFlag.Short('h')
|
kingpin.HelpFlag.Short('h')
|
||||||
kingpin.Version(versionMessage())
|
kingpin.Version(versionMessage())
|
||||||
@@ -110,17 +115,18 @@ func parseFlags() error {
|
|||||||
kingpin.Flag("cert", "tls cert.pem path").StringVar(&gcfg.Cert)
|
kingpin.Flag("cert", "tls cert.pem path").StringVar(&gcfg.Cert)
|
||||||
kingpin.Flag("key", "tls key.pem path").StringVar(&gcfg.Key)
|
kingpin.Flag("key", "tls key.pem path").StringVar(&gcfg.Key)
|
||||||
kingpin.Flag("auth-type", "Auth type <http|openid>").StringVar(&gcfg.Auth.Type)
|
kingpin.Flag("auth-type", "Auth type <http|openid>").StringVar(&gcfg.Auth.Type)
|
||||||
kingpin.Flag("auth-http", "HTTP basic auth (ex: user:pass)").StringVar(&gcfg.Auth.HTTP)
|
kingpin.Flag("auth-http", "HTTP basic auth (ex: user:pass)").StringsVar(&gcfg.Auth.HTTP)
|
||||||
kingpin.Flag("auth-openid", "OpenID auth identity url").StringVar(&gcfg.Auth.OpenID)
|
kingpin.Flag("auth-openid", "OpenID auth identity url").StringVar(&gcfg.Auth.OpenID)
|
||||||
kingpin.Flag("theme", "web theme, one of <black|green>").StringVar(&gcfg.Theme)
|
kingpin.Flag("theme", "web theme, one of <black|green>").StringVar(&gcfg.Theme)
|
||||||
kingpin.Flag("upload", "enable upload support").BoolVar(&gcfg.Upload)
|
kingpin.Flag("upload", "enable upload support").BoolVar(&gcfg.Upload)
|
||||||
kingpin.Flag("delete", "enable delete support").BoolVar(&gcfg.Delete)
|
kingpin.Flag("delete", "enable delete support").BoolVar(&gcfg.Delete)
|
||||||
kingpin.Flag("xheaders", "used when behide nginx").BoolVar(&gcfg.XHeaders)
|
kingpin.Flag("xheaders", "used when behide nginx").BoolVar(&gcfg.XHeaders)
|
||||||
kingpin.Flag("cors", "enable cross-site HTTP request").BoolVar(&gcfg.Cors)
|
|
||||||
kingpin.Flag("debug", "enable debug mode").BoolVar(&gcfg.Debug)
|
kingpin.Flag("debug", "enable debug mode").BoolVar(&gcfg.Debug)
|
||||||
kingpin.Flag("plistproxy", "plist proxy when server is not https").Short('p').StringVar(&gcfg.PlistProxy)
|
kingpin.Flag("plistproxy", "plist proxy when server is not https").Short('p').StringVar(&gcfg.PlistProxy)
|
||||||
kingpin.Flag("title", "server title").StringVar(&gcfg.Title)
|
kingpin.Flag("title", "server title").StringVar(&gcfg.Title)
|
||||||
kingpin.Flag("google-tracker-id", "set to empty to disable it").StringVar(&gcfg.GoogleTrackerID)
|
kingpin.Flag("google-tracker-id", "set to empty to disable it").StringVar(&gcfg.GoogleTrackerID)
|
||||||
|
kingpin.Flag("deep-path-max-depth", "set to -1 to not combine dirs").IntVar(&gcfg.DeepPathMaxDepth)
|
||||||
|
kingpin.Flag("no-index", "disable indexing").BoolVar(&gcfg.NoIndex)
|
||||||
|
|
||||||
kingpin.Parse() // first parse conf
|
kingpin.Parse() // first parse conf
|
||||||
|
|
||||||
@@ -148,6 +154,41 @@ func fixPrefix(prefix string) string {
|
|||||||
return prefix
|
return prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cors(next http.Handler) http.Handler {
|
||||||
|
// access control and CORS middleware
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||||
|
if r.Method == "OPTIONS" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiBasicAuth(auths []string) func(http.Handler) http.Handler {
|
||||||
|
userPassMap := make(map[string]string)
|
||||||
|
for _, auth := range auths {
|
||||||
|
userpass := strings.SplitN(auth, ":", 2)
|
||||||
|
if len(userpass) == 2 {
|
||||||
|
userPassMap[userpass[0]] = userpass[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpauth.BasicAuth(httpauth.AuthOptions{
|
||||||
|
Realm: "Restricted",
|
||||||
|
AuthFunc: func(user, pass string, request *http.Request) bool {
|
||||||
|
password, ok := userPassMap[user]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
givenPass := sha256.Sum256([]byte(pass))
|
||||||
|
requiredPass := sha256.Sum256([]byte(password))
|
||||||
|
return subtle.ConstantTimeCompare(givenPass[:], requiredPass[:]) == 1
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := parseFlags(); err != nil {
|
if err := parseFlags(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -164,7 +205,7 @@ func main() {
|
|||||||
log.Printf("url prefix: %s", gcfg.Prefix)
|
log.Printf("url prefix: %s", gcfg.Prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := NewHTTPStaticServer(gcfg.Root)
|
ss := NewHTTPStaticServer(gcfg.Root, gcfg.NoIndex)
|
||||||
ss.Prefix = gcfg.Prefix
|
ss.Prefix = gcfg.Prefix
|
||||||
ss.Theme = gcfg.Theme
|
ss.Theme = gcfg.Theme
|
||||||
ss.Title = gcfg.Title
|
ss.Title = gcfg.Title
|
||||||
@@ -172,6 +213,7 @@ func main() {
|
|||||||
ss.Upload = gcfg.Upload
|
ss.Upload = gcfg.Upload
|
||||||
ss.Delete = gcfg.Delete
|
ss.Delete = gcfg.Delete
|
||||||
ss.AuthType = gcfg.Auth.Type
|
ss.AuthType = gcfg.Auth.Type
|
||||||
|
ss.DeepPathMaxDepth = gcfg.DeepPathMaxDepth
|
||||||
|
|
||||||
if gcfg.PlistProxy != "" {
|
if gcfg.PlistProxy != "" {
|
||||||
u, err := url.Parse(gcfg.PlistProxy)
|
u, err := url.Parse(gcfg.PlistProxy)
|
||||||
@@ -190,13 +232,9 @@ func main() {
|
|||||||
hdlr = accesslog.NewLoggingHandler(hdlr, logger)
|
hdlr = accesslog.NewLoggingHandler(hdlr, logger)
|
||||||
|
|
||||||
// HTTP Basic Authentication
|
// HTTP Basic Authentication
|
||||||
userpass := strings.SplitN(gcfg.Auth.HTTP, ":", 2)
|
|
||||||
switch gcfg.Auth.Type {
|
switch gcfg.Auth.Type {
|
||||||
case "http":
|
case "http":
|
||||||
if len(userpass) == 2 {
|
hdlr = multiBasicAuth(gcfg.Auth.HTTP)(hdlr)
|
||||||
user, pass := userpass[0], userpass[1]
|
|
||||||
hdlr = httpauth.SimpleBasicAuth(user, pass)(hdlr)
|
|
||||||
}
|
|
||||||
case "openid":
|
case "openid":
|
||||||
handleOpenID(gcfg.Auth.OpenID, false) // FIXME(ssx): set secure default to false
|
handleOpenID(gcfg.Auth.OpenID, false) // FIXME(ssx): set secure default to false
|
||||||
// case "github":
|
// case "github":
|
||||||
@@ -206,9 +244,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CORS
|
// CORS
|
||||||
if gcfg.Cors {
|
hdlr = cors(hdlr)
|
||||||
hdlr = handlers.CORS(handlers.AllowedMethods([]string{"GET", "HEAD", "OPTIONS"}))(hdlr)
|
|
||||||
}
|
|
||||||
if gcfg.XHeaders {
|
if gcfg.XHeaders {
|
||||||
hdlr = handlers.ProxyHeaders(hdlr)
|
hdlr = handlers.ProxyHeaders(hdlr)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user