Skip to content

Commit 0416383

Browse files
committed
feat: Webdav server
1 parent 6b60521 commit 0416383

File tree

10 files changed

+283
-84
lines changed

10 files changed

+283
-84
lines changed

cmd/flydav/app/args.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package app
22

33
type Args struct {
4-
Names []string `arg:"positional,required" help:"names to flydav"`
5-
Seperately bool `arg:"-s,--seperately" help:"flydav each name seperately" default:"false"`
6-
Verbose bool `arg:"-v,--verbose" help:"verbose output" default:"false"`
7-
Config string `arg:"-c,--config" help:"config file" default:"config.toml"`
4+
Host string `arg:"-H,--host" help:"host address"`
5+
Port int `arg:"-p,--port" help:"port"`
6+
Username string `arg:"-u,--user" help:"username"`
7+
Verbose bool `arg:"-v,--verbose" help:"verbose output"`
8+
Config string `arg:"-c,--config" help:"config file"`
89
}

cmd/flydav/app/entry.go

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/pluveto/flydav/cmd/flydav/conf"
7+
"github.com/pluveto/flydav/cmd/flydav/service"
8+
)
9+
10+
func Run(conf conf.Conf) {
11+
12+
fmt.Println("Serving on: ", fmt.Sprintf("%s:%d", conf.Server.Host, conf.Server.Port))
13+
fmt.Println("Username: ", conf.Auth.User[0].Username)
14+
// fmt.Println("Password(Encrypted): ", conf.Auth.User[0].PasswordHash)
15+
16+
server := &WebdavServer{
17+
AuthService: &service.BasicAuthService{Users: conf.Auth.User},
18+
Host: conf.Server.Host,
19+
Port: conf.Server.Port,
20+
}
21+
server.Listen()
22+
}

cmd/flydav/app/handler.go

-25
This file was deleted.

cmd/flydav/app/logger.go

+34-11
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import (
44
"os"
55

66
"github.com/natefinch/lumberjack"
7+
"github.com/pluveto/flydav/cmd/flydav/conf"
78
"github.com/pluveto/flydav/pkg/logger"
89
"github.com/sirupsen/logrus"
910
)
1011

11-
func InitLogger(conf Log, verbose bool) {
12-
newLoggerCount := len(conf.Stdout) + len(conf.File)
12+
func InitLogger(cnf conf.Log, verbose bool) {
13+
newLoggerCount := len(cnf.Stdout) + len(cnf.File)
1314
if newLoggerCount != 0 {
1415
for i := 0; i < newLoggerCount; i++ {
1516
logger.AddLogger(logrus.New())
@@ -22,33 +23,33 @@ func InitLogger(conf Log, verbose bool) {
2223
// enable source code line numbers
2324
logger.SetReportCaller(true)
2425
} else {
25-
logger.SetLevel(levelToLogrusLevel(conf.Level))
26+
logger.SetLevel(levelToLogrusLevel(cnf.Level))
2627
}
2728

28-
for _, stdout := range conf.Stdout {
29+
for _, stdout := range cnf.Stdout {
2930
currentLogger := logger.DefaultCombinedLogger.GetLogger(nextLoggerIndex)
3031
switch stdout.Format {
31-
case LogFormatJSON:
32+
case conf.LogFormatJSON:
3233
currentLogger.SetFormatter(&logrus.JSONFormatter{})
33-
case LogFormatText:
34+
case conf.LogFormatText:
3435
currentLogger.SetFormatter(&logrus.TextFormatter{})
3536
}
3637
switch stdout.Output {
37-
case LogOutputStdout:
38+
case conf.LogOutputStdout:
3839
currentLogger.SetOutput(os.Stdout)
39-
case LogOutputStderr:
40+
case conf.LogOutputStderr:
4041
currentLogger.SetOutput(os.Stderr)
4142
}
4243
nextLoggerIndex++
4344
}
4445

45-
for _, file := range conf.File {
46+
for _, file := range cnf.File {
4647
currentLogger := logger.DefaultCombinedLogger.GetLogger(nextLoggerIndex)
4748

4849
switch file.Format {
49-
case LogFormatJSON:
50+
case conf.LogFormatJSON:
5051
currentLogger.SetFormatter(&logrus.JSONFormatter{})
51-
case LogFormatText:
52+
case conf.LogFormatText:
5253
currentLogger.SetFormatter(&logrus.TextFormatter{})
5354
}
5455
currentLogger.SetOutput(&lumberjack.Logger{
@@ -62,3 +63,25 @@ func InitLogger(conf Log, verbose bool) {
6263
}
6364

6465
}
66+
67+
// levelToLogrusLevel converts a string to a logrus.Level
68+
func levelToLogrusLevel(level string) logrus.Level {
69+
switch level {
70+
case "debug":
71+
return logrus.DebugLevel
72+
case "info":
73+
return logrus.InfoLevel
74+
case "warn":
75+
return logrus.WarnLevel
76+
case "warning":
77+
return logrus.WarnLevel
78+
case "error":
79+
return logrus.ErrorLevel
80+
case "fatal":
81+
return logrus.FatalLevel
82+
case "panic":
83+
return logrus.PanicLevel
84+
default:
85+
return logrus.InfoLevel
86+
}
87+
}

cmd/flydav/app/server.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package app
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"path"
7+
"strings"
8+
9+
"github.com/pluveto/flydav/pkg/logger"
10+
"github.com/sirupsen/logrus"
11+
"golang.org/x/net/webdav"
12+
)
13+
14+
type AuthService interface {
15+
Authenticate(username, password string) error
16+
}
17+
18+
type WebdavServer struct {
19+
AuthService AuthService
20+
Host string
21+
Port int
22+
MappedDir string
23+
}
24+
25+
func (s *WebdavServer) Listen() {
26+
if nil == s.AuthService {
27+
logger.Fatal("AuthService is nil")
28+
}
29+
if s.MappedDir == "" {
30+
logger.Fatal("MappedDir is empty")
31+
}
32+
if !path.IsAbs(s.MappedDir) {
33+
logger.Fatal("MappedDir is not an absolute path")
34+
}
35+
if !strings.HasPrefix(s.MappedDir, "/home/") {
36+
logger.Warn("You're using a path which isn't under /home/ as mapped directory. This may cause security issues.")
37+
}
38+
39+
davfs := &webdav.Handler{
40+
FileSystem: webdav.Dir(s.MappedDir),
41+
LockSystem: webdav.NewMemLS(),
42+
Logger: func(r *http.Request, err error) {
43+
ent := logger.WithFields(logrus.Fields{
44+
"method": r.Method,
45+
"path": r.URL.Path,
46+
})
47+
if err != nil {
48+
ent.Error(err)
49+
} else {
50+
ent.Info()
51+
}
52+
},
53+
}
54+
55+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
56+
username, password, ok := r.BasicAuth()
57+
if !ok {
58+
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
59+
http.Error(w, "Unauthorized.", http.StatusUnauthorized)
60+
return
61+
}
62+
err := s.AuthService.Authenticate(username, password)
63+
if err != nil {
64+
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
65+
http.Error(w, "Unauthorized.", http.StatusUnauthorized)
66+
logger.Error("Unauthorized: ", err)
67+
return
68+
}
69+
davfs.ServeHTTP(w, r)
70+
})
71+
addr := fmt.Sprintf("%s:%d", s.Host, s.Port)
72+
err := http.ListenAndServe(addr, nil)
73+
logger.Fatal("failed to listen and serve on", addr, ":", err)
74+
}

cmd/flydav/app/conf.go cmd/flydav/conf/conf.go

+47-35
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
1-
package app
1+
package conf
22

3-
import "github.com/sirupsen/logrus"
3+
import (
4+
"golang.org/x/crypto/bcrypt"
5+
)
6+
7+
func GetDefaultConf() Conf {
8+
return Conf{
9+
Log: Log{
10+
Level: "warn",
11+
Stdout: []Stdout{},
12+
File: []File{},
13+
},
14+
Server: Server{
15+
Host: "127.0.0.1",
16+
Port: 7086,
17+
},
18+
Auth: Auth{
19+
User: []User{
20+
{
21+
Username: "flydav",
22+
PasswordHash: (func() string {
23+
b, _ := bcrypt.GenerateFromPassword([]byte("flydav"), bcrypt.DefaultCost)
24+
return string(b)
25+
})(),
26+
PasswordCrypt: "bcrypt",
27+
},
28+
},
29+
},
30+
}
31+
}
432

533
type Conf struct {
6-
Log Log `toml:"log"`
34+
Log Log `toml:"log"`
35+
Server Server `toml:"server"`
36+
Auth Auth `toml:"auth"`
37+
}
38+
39+
type Server struct {
40+
Host string `toml:"host"`
41+
Port int `toml:"port"`
42+
}
43+
type User struct {
44+
Username string `toml:"username"`
45+
PasswordHash string `toml:"password_hash"`
46+
PasswordCrypt string `toml:"password_crypt"`
747
}
48+
type Auth struct {
49+
User []User `toml:"user"`
50+
}
51+
852
type File struct {
953
Format LogFormat `toml:"format"`
1054
Path string `toml:"path"`
@@ -36,35 +80,3 @@ type Log struct {
3680
File []File `toml:"file"`
3781
Stdout []Stdout `toml:"stdout"`
3882
}
39-
40-
func GetDefaultConf() Conf {
41-
return Conf{
42-
Log: Log{
43-
Level: "warn",
44-
Stdout: []Stdout{},
45-
File: []File{},
46-
},
47-
}
48-
}
49-
50-
// levelToLogrusLevel converts a string to a logrus.Level
51-
func levelToLogrusLevel(level string) logrus.Level {
52-
switch level {
53-
case "debug":
54-
return logrus.DebugLevel
55-
case "info":
56-
return logrus.InfoLevel
57-
case "warn":
58-
return logrus.WarnLevel
59-
case "warning":
60-
return logrus.WarnLevel
61-
case "error":
62-
return logrus.ErrorLevel
63-
case "fatal":
64-
return logrus.FatalLevel
65-
case "panic":
66-
return logrus.PanicLevel
67-
default:
68-
return logrus.InfoLevel
69-
}
70-
}

0 commit comments

Comments
 (0)