From df4b25de98f747f1c491d7eb7902fe536e2b4b12 Mon Sep 17 00:00:00 2001 From: Timo Ley Date: Sun, 6 Sep 2020 00:08:01 +0200 Subject: [PATCH] Init --- .gitignore | 2 ++ go.mod | 10 ++++++++ go.sum | 15 +++++++++++ main.go | 50 ++++++++++++++++++++++++++++++++++++ maven/config.go | 20 +++++++++++++++ maven/server.go | 52 ++++++++++++++++++++++++++++++++++++++ maven/sql.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 216 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 maven/config.go create mode 100644 maven/server.go create mode 100644 maven/sql.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2feb6d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +config.yaml +.idea \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e418e58 --- /dev/null +++ b/go.mod @@ -0,0 +1,10 @@ +module mavenserver + +go 1.15 + +require ( + github.com/go-sql-driver/mysql v1.5.0 + github.com/gorilla/mux v1.8.0 + github.com/jmoiron/sqlx v1.2.0 + gopkg.in/yaml.v2 v2.3.0 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a9827c6 --- /dev/null +++ b/go.sum @@ -0,0 +1,15 @@ +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= +github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= +github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= +github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= +github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..de86e36 --- /dev/null +++ b/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "gopkg.in/yaml.v2" + "mavenserver/maven" + "os" +) + +func main() { + var auth maven.AuthManager + config := readconf("config.yaml") + auth = maven.Create(config.Database) + maven.StartServer(config.Server, &auth) +} + +func readconf(loc string) maven.Configuration { + if _, err := os.Stat(loc); os.IsNotExist(err) { + conf := ` +server: + port: 8080 + mavenpath: "maven" + basepath: "/maven" +database: + host: "localhost" + database: "mavenusers" + username: "root" + password: "password"` + file, err := os.Create(loc) + if err != nil { + panic(err) + } + defer file.Close() + _, err = file.WriteString(conf) + if err != nil { + panic(err) + } + } + file, err := os.Open(loc) + if err != nil { + panic(err) + } + defer file.Close() + var conf maven.Configuration + dec := yaml.NewDecoder(file) + err = dec.Decode(&conf) + if err != nil { + panic(err) + } + return conf +} diff --git a/maven/config.go b/maven/config.go new file mode 100644 index 0000000..b984e48 --- /dev/null +++ b/maven/config.go @@ -0,0 +1,20 @@ +package maven + +type ServerConf struct { + Port int `yaml:"port"` + MavenPath string `yaml:"mavenpath"` + BasePath string `yaml:"basepath"` +} + +type DSN struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + Host string `yaml:"host"` + Port int `yaml:"port"` + Database string `yaml:"database"` +} + +type Configuration struct { + Database DSN `yaml:"database"` + Server ServerConf `yaml:"server"` +} diff --git a/maven/server.go b/maven/server.go new file mode 100644 index 0000000..6c36729 --- /dev/null +++ b/maven/server.go @@ -0,0 +1,52 @@ +package maven + +import ( + "github.com/gorilla/mux" + "io" + "net/http" + "os" + "path" + "strconv" +) + +type PutHandler struct { + rootpath string + auth *AuthManager +} + +type AuthManager interface { + HasAccess(path string, username string, password string) bool +} + +func StartServer(conf ServerConf, auth *AuthManager) { + handler := mux.NewRouter() + handler.PathPrefix(conf.BasePath).Methods("GET").Handler(http.StripPrefix(conf.BasePath, http.FileServer(http.Dir(conf.MavenPath)))) + handler.PathPrefix(conf.BasePath).Methods("PUT").Handler(http.StripPrefix(conf.BasePath, PutHandler{rootpath: conf.MavenPath, auth: auth})) + err := http.ListenAndServe("0.0.0.0:"+strconv.Itoa(conf.Port), handler) + if err != nil { + panic(err) + } +} + +func (h PutHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) { + filepath := h.rootpath + req.URL.Path + auth := *h.auth + username, password, _ := req.BasicAuth() + if auth.HasAccess(req.URL.Path, username, password) { + err := os.MkdirAll(path.Dir(filepath), 0777) + if err != nil { + http.Error(res, err.Error(), http.StatusInternalServerError) + } + f, err := os.OpenFile(filepath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) + defer f.Close() + if err != nil { + http.Error(res, err.Error(), http.StatusInternalServerError) + } + _, err = io.Copy(f, req.Body) + if err != nil { + http.Error(res, err.Error(), http.StatusInternalServerError) + } + } else { + http.Error(res, "No Permission", http.StatusForbidden) + } +} diff --git a/maven/sql.go b/maven/sql.go new file mode 100644 index 0000000..0b649f3 --- /dev/null +++ b/maven/sql.go @@ -0,0 +1,67 @@ +package maven + +import ( + "crypto/md5" + "encoding/hex" + _ "github.com/go-sql-driver/mysql" + "github.com/jmoiron/sqlx" + "strconv" + "time" +) + +func Create(con DSN) Database { + connec, err := sqlx.Open("mysql", con.Format()) + if err != nil { + panic(err) + } + connec.SetConnMaxLifetime(time.Minute * 3) + connec.SetMaxOpenConns(10) + return Database{db: connec} +} + +func (d DSN) Format() string { + fm := "" + if d.Username != "" { + fm += d.Username + if d.Password != "" { + fm += ":" + fm += d.Password + } + fm += "@" + } + if d.Host != "" { + fm += "(" + fm += d.Host + if d.Port != 0 { + fm += ":" + fm += strconv.Itoa(d.Port) + } + fm += ")" + } + fm += "/" + fm += d.Database + return fm +} + +type Database struct { + db *sqlx.DB +} + +type User struct { + Password string `DB:"password"` +} + +func (d Database) HasAccess(path string, username string, password string) bool { + row := d.db.QueryRowx("SELECT password FROM users WHERE username=?", username) + user := User{} + err := row.StructScan(&user) + if err != nil { + return false + } + return user.Password == Hash(password) +} + +func Hash(input string) string { + hash := md5.Sum([]byte(input)) + return hex.EncodeToString(hash[:]) +}