Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdd6ff9435 | ||
|
|
29bd44ac0c | ||
|
|
4b9be2fd12 | ||
|
|
2d7a0f1aaf | ||
|
|
23f70c844a | ||
|
|
6d8af0af8f | ||
|
|
189100b3af |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -29,6 +29,6 @@ jobs:
|
||||
# either 'goreleaser' (default) or 'goreleaser-pro'
|
||||
distribution: goreleaser
|
||||
version: latest
|
||||
args: release --rm-dist
|
||||
args: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
version: 2
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
@@ -16,8 +17,16 @@ builds:
|
||||
- "386"
|
||||
goarm:
|
||||
- "6"
|
||||
brews:
|
||||
- tap:
|
||||
owner: codeskyblue
|
||||
name: homebrew-tap
|
||||
folder: Formula
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
|
||||
# brews:
|
||||
# - tap:
|
||||
# owner: codeskyblue
|
||||
# name: homebrew-tap
|
||||
# folder: Formula
|
||||
|
||||
@@ -91,7 +91,7 @@ Share current directory with http basic auth
|
||||
```bash
|
||||
$ docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name 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.)
|
||||
@@ -113,7 +113,7 @@ $ docker build -t codeskyblue/gohttpserver -f docker/Dockerfile .
|
||||
- Enable basic http authentication
|
||||
|
||||
```sh
|
||||
$ gohttpserver --auth-type http --auth-http username:password
|
||||
$ gohttpserver --auth-type http --auth-http username1:password1 --auth-http username2:password2
|
||||
```
|
||||
|
||||
- Use openid auth
|
||||
|
||||
@@ -239,7 +239,15 @@ var vm = new Vue({
|
||||
var reqPath = this.getEncodePath(f.name)
|
||||
// TODO: fix here tomorrow
|
||||
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;
|
||||
}
|
||||
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>
|
||||
4
go.mod
4
go.mod
@@ -19,7 +19,7 @@ require (
|
||||
github.com/shogo82148/androidbinary v0.0.0-20180627093851-01c4bfa8b3b5
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/text v0.13.0
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/text v0.14.0
|
||||
howett.net/plist v0.0.0-20201203080718-1454fab16a06 // indirect
|
||||
)
|
||||
|
||||
18
go.sum
18
go.sum
@@ -54,7 +54,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
|
||||
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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
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=
|
||||
@@ -63,8 +64,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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=
|
||||
@@ -75,19 +77,21 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
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.13.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.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
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.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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
||||
@@ -103,6 +103,7 @@ func NewHTTPStaticServer(root string, noIndex bool) *HTTPStaticServer {
|
||||
// routers for Apple *.ipa
|
||||
m.HandleFunc("/-/ipa/plist/{path:.*}", s.hPlist)
|
||||
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.hUploadOrMkdir).Methods("POST")
|
||||
@@ -816,3 +817,28 @@ func checkFilename(name string) error {
|
||||
}
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
42
main.go
42
main.go
@@ -2,6 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@@ -42,11 +44,11 @@ type Configure struct {
|
||||
Debug bool `yaml:"debug"`
|
||||
GoogleTrackerID string `yaml:"google-tracker-id"`
|
||||
Auth struct {
|
||||
Type string `yaml:"type"` // openid|http|github
|
||||
OpenID string `yaml:"openid"`
|
||||
HTTP string `yaml:"http"`
|
||||
ID string `yaml:"id"` // for oauth2
|
||||
Secret string `yaml:"secret"` // for oauth2
|
||||
Type string `yaml:"type"` // openid|http|github
|
||||
OpenID string `yaml:"openid"`
|
||||
HTTP []string `yaml:"http"`
|
||||
ID string `yaml:"id"` // for oauth2
|
||||
Secret string `yaml:"secret"` // for oauth2
|
||||
} `yaml:"auth"`
|
||||
DeepPathMaxDepth int `yaml:"deep-path-max-depth"`
|
||||
NoIndex bool `yaml:"no-index"`
|
||||
@@ -113,7 +115,7 @@ func parseFlags() error {
|
||||
kingpin.Flag("cert", "tls cert.pem path").StringVar(&gcfg.Cert)
|
||||
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-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("theme", "web theme, one of <black|green>").StringVar(&gcfg.Theme)
|
||||
kingpin.Flag("upload", "enable upload support").BoolVar(&gcfg.Upload)
|
||||
@@ -165,6 +167,28 @@ func cors(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
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() {
|
||||
if err := parseFlags(); err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -208,13 +232,9 @@ func main() {
|
||||
hdlr = accesslog.NewLoggingHandler(hdlr, logger)
|
||||
|
||||
// HTTP Basic Authentication
|
||||
userpass := strings.SplitN(gcfg.Auth.HTTP, ":", 2)
|
||||
switch gcfg.Auth.Type {
|
||||
case "http":
|
||||
if len(userpass) == 2 {
|
||||
user, pass := userpass[0], userpass[1]
|
||||
hdlr = httpauth.SimpleBasicAuth(user, pass)(hdlr)
|
||||
}
|
||||
hdlr = multiBasicAuth(gcfg.Auth.HTTP)(hdlr)
|
||||
case "openid":
|
||||
handleOpenID(gcfg.Auth.OpenID, false) // FIXME(ssx): set secure default to false
|
||||
// case "github":
|
||||
|
||||
Reference in New Issue
Block a user