-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.go
131 lines (120 loc) · 3.82 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package main
import (
"context"
"fmt"
"log"
"net/http"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"github.com/spf13/cobra"
"golang.org/x/net/webdav"
"golang.org/x/sync/errgroup"
)
type ctxKey int
var minioClientCtxKey ctxKey
var (
port uint
endpoint string
region string
secure bool
preferDirectory bool // Minio does not allow duplicate names for directory and file names, but s3 does.
allowBucketsOps bool
readOnly bool
inMemory bool
verbose bool
tlsCert string
tlsKey string
username string // for debug
password string // for debug
)
var RootCmd = &cobra.Command{
Use: "s3dav-proxy",
Run: func(cmd *cobra.Command, args []string) {
srv := &webdav.Handler{
FileSystem: newHandler(),
LockSystem: webdav.NewMemLS(),
Logger: func(r *http.Request, err error) {
if verbose {
log.Printf("%s %s %v", r.Method, r.URL, err)
}
},
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
_username, _password, _ := r.BasicAuth()
if username != "" {
_username = username
}
if password != "" {
_password = password
}
mc, err := minio.New(endpoint, &minio.Options{
Creds: credentials.NewStaticV4(_username, _password, ""),
Secure: secure,
Region: region,
})
if err != nil {
if verbose {
log.Println(err)
}
w.WriteHeader(http.StatusInternalServerError)
return
}
if r.Method == "PROPFIND" {
if _, err := mc.ListBuckets(context.Background()); err != nil {
if minioErr, ok := err.(minio.ErrorResponse); ok {
log.Println(minioErr.Code)
if minioErr.Code == "SignatureDoesNotMatch" || minioErr.Code == "InvalidAccessKeyId" || minioErr.Code == "AccessDenied" {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
w.WriteHeader(http.StatusUnauthorized)
return
}
}
if verbose {
log.Println(err)
}
w.WriteHeader(http.StatusInternalServerError)
return
}
} else {
if _username == "" || _password == "" {
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`)
w.WriteHeader(http.StatusUnauthorized)
return
}
}
srv.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), minioClientCtxKey, mc)))
})
eg := errgroup.Group{}
eg.Go(func() error {
if tlsCert != "" && tlsKey != "" {
return http.ListenAndServeTLS(fmt.Sprintf(":%d", port), tlsCert, tlsKey, nil)
} else {
return http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}
})
log.Printf("Listening on port %d", port)
if err := eg.Wait(); err != nil {
log.Fatal(err)
}
},
}
func init() {
RootCmd.Flags().StringVarP(&endpoint, "endpoint", "e", "localhost:9000", "Minio endpoint")
RootCmd.Flags().StringVarP(®ion, "region", "r", "", "Region(for S3)")
RootCmd.Flags().BoolVarP(&secure, "secure", "s", false, "Use secure connection")
RootCmd.Flags().UintVarP(&port, "port", "p", 8080, "Port to listen on")
RootCmd.Flags().BoolVarP(&preferDirectory, "prefer-directory", "d", true, "Prefer directory over file")
RootCmd.Flags().BoolVarP(&allowBucketsOps, "allow-buckets-ops", "b", false, "Allow operations on buckets")
RootCmd.Flags().BoolVarP(&readOnly, "ro", "", false, "Read only")
RootCmd.Flags().BoolVarP(&inMemory, "in-memory", "m", false, "In memory(upload)")
RootCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Verbose output")
RootCmd.Flags().StringVarP(&tlsCert, "tls-cert", "c", "", "TLS certificate")
RootCmd.Flags().StringVarP(&tlsKey, "tls-key", "k", "", "TLS key")
RootCmd.Flags().StringVarP(&username, "username", "U", "", "Username")
RootCmd.Flags().MarkHidden("username")
RootCmd.Flags().StringVarP(&password, "password", "P", "", "Password")
RootCmd.Flags().MarkHidden("password")
}
func main() {
RootCmd.Execute()
}