# HG changeset patch # User Thomas Junk # Date 1533045371 -7200 # Node ID b1116c4ce57feaafad4b329c9e419066ef125002 # Parent 22deb76dff2ce51e62820854e6d23f2ed00a7dca# Parent c2334b5d3dd0eeb71325b43365b02edc6582c5db merge with default diff -r 22deb76dff2c -r b1116c4ce57f README.md --- a/README.md Tue Jul 31 15:01:10 2018 +0200 +++ b/README.md Tue Jul 31 15:56:11 2018 +0200 @@ -9,6 +9,8 @@ - To only build the SPA-Client you can use `make client`. +For further details see [docs/DEVELOPMENT](docs/DEVELOPMENT.md), + ## Setup Database @@ -41,31 +43,3 @@ - `./cmd/gemma/gemma -h` gives you an overview of more available options. - - -# Manual setup - -## Backend - -In Go. - -* Install dependencies - - `sh 3rdpartylibs` - -* Build - - Prerequesite: compile server - ``` - cd cmd/gemma/ - go build - cd ../../ - ``` - -* Run - Run server with `./cmd/gemma/gemma` - - -## Client - -See [client/README](client/README.md). diff -r 22deb76dff2c -r b1116c4ce57f cmd/gemma/root.go --- a/cmd/gemma/root.go Tue Jul 31 15:01:10 2018 +0200 +++ b/cmd/gemma/root.go Tue Jul 31 15:56:11 2018 +0200 @@ -38,7 +38,7 @@ fl().StringVarP(&config.Config.DBHost, "dbhost", "H", "localhost", "host of the database") fl().UintVarP(&config.Config.DBPort, "dbport", "P", 5432, "port of the database") fl().StringVarP(&config.Config.DBName, "dbname", "d", "gemma", "name of the database") - fl().StringVarP(&config.Config.DBSSLMode, "dbssl", "S", "require", "SSL mode of the database") + fl().StringVarP(&config.Config.DBSSLMode, "dbssl", "S", "prefer", "SSL mode of the database") fl().StringVarP(&config.Config.SessionStore, "sessions", "s", "", "path to the sessions file") diff -r 22deb76dff2c -r b1116c4ce57f controllers/token.go --- a/controllers/token.go Tue Jul 31 15:01:10 2018 +0200 +++ b/controllers/token.go Tue Jul 31 15:56:11 2018 +0200 @@ -9,6 +9,13 @@ "gemma.intevation.de/gemma/auth" ) +func sendJSON(rw http.ResponseWriter, data interface{}) { + rw.Header().Set("Content-Type", "application/json") + if err := json.NewEncoder(rw).Encode(data); err != nil { + log.Printf("error: %v\n", err) + } +} + func renew(rw http.ResponseWriter, req *http.Request) { token, _ := auth.GetToken(req) newToken, err := auth.ConnPool.Renew(token) @@ -35,10 +42,7 @@ Roles: session.Roles, } - rw.Header().Set("Content-Type", "text/plain") - if err := json.NewEncoder(rw).Encode(&result); err != nil { - log.Printf("error: %v\n", err) - } + sendJSON(rw, &result) } func logout(rw http.ResponseWriter, req *http.Request) { @@ -53,11 +57,18 @@ } func login(rw http.ResponseWriter, req *http.Request) { - user := req.FormValue("user") - password := req.FormValue("password") + + var ( + user = req.FormValue("user") + password = req.FormValue("password") + ) + + if user == "" || password == "" { + http.Error(rw, "Invalid credentials", http.StatusBadRequest) + return + } token, session, err := auth.GenerateSession(user, password) - if err != nil { http.Error(rw, fmt.Sprintf("error: %v", err), http.StatusInternalServerError) return @@ -75,8 +86,5 @@ Roles: session.Roles, } - rw.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(rw).Encode(&result); err != nil { - log.Printf("error: %v\n", err) - } + sendJSON(rw, &result) } diff -r 22deb76dff2c -r b1116c4ce57f controllers/types.go --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controllers/types.go Tue Jul 31 15:56:11 2018 +0200 @@ -0,0 +1,146 @@ +package controllers + +import ( + "database/sql/driver" + "encoding/json" + "errors" + "regexp" + "strings" +) + +type ( + Email string + Country string + Role string + + BoundingBox struct { + X1 float64 `json:"x1"` + Y1 float64 `json:"y1"` + X2 float64 `json:"x2"` + Y2 float64 `json:"y2"` + } + + User struct { + User string `json:"user"` + Role Role `json:"role"` + Password string `json:"password,omitempty"` + Email Email `json:"email"` + Country Country `json:"country"` + Extent *BoundingBox `json:"extent"` + } +) + +var ( + // https://stackoverflow.com/questions/201323/how-to-validate-an-email-address-using-a-regular-expression + emailRe = regexp.MustCompile( + `(?:[a-z0-9!#$%&'*+/=?^_` + "`" + + `{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_` + "`" + + `{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]` + + `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")` + + `@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?` + + `|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}` + + `(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]` + + `:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]` + + `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])`) + + errNoEmailAddress = errors.New("Not a valid email address") + errNoString = errors.New("Not a string") +) + +func (e *Email) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + if !emailRe.MatchString(s) { + return errNoEmailAddress + } + *e = Email(s) + return nil +} + +func (e Email) Value() (driver.Value, error) { + return string(e), nil +} + +func (e *Email) Scan(src interface{}) (err error) { + if s, ok := src.(string); ok { + *e = Email(s) + } else { + err = errNoString + } + return +} + +var ( + validCountries = []string{ + "AT", "BG", "DE", "HU", "HR", + "MD", "RO", "RS", "SK", "UA", + } + errNoValidCountry = errors.New("Not a valid country") +) + +func (c *Country) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + s = strings.ToUpper(s) + for _, v := range validCountries { + if v == s { + *c = Country(v) + return nil + } + } + return errNoValidCountry +} + +func (c Country) Value() (driver.Value, error) { + return string(c), nil +} + +func (c *Country) Scan(src interface{}) (err error) { + if s, ok := src.(string); ok { + *c = Country(s) + } else { + err = errNoString + } + return +} + +var ( + validRoles = []string{ + "waterway_user", + "waterway_admin", + "sys_admin", + } + errNoValidRole = errors.New("Not a valid role") +) + +func (r Role) Value() (driver.Value, error) { + return string(r), nil +} + +func (r *Role) Scan(src interface{}) (err error) { + if s, ok := src.(string); ok { + *r = Role(s) + } else { + err = errNoString + } + return +} + +func (r *Role) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + s = strings.ToLower(s) + for _, v := range validRoles { + if v == s { + *r = Role(v) + return nil + } + } + return errNoValidRole +} diff -r 22deb76dff2c -r b1116c4ce57f controllers/user.go --- a/controllers/user.go Tue Jul 31 15:01:10 2018 +0200 +++ b/controllers/user.go Tue Jul 31 15:56:11 2018 +0200 @@ -2,41 +2,14 @@ import ( "database/sql" - "database/sql/driver" - "encoding/json" - "errors" "fmt" "net/http" - "regexp" - "strings" "github.com/gorilla/mux" "gemma.intevation.de/gemma/auth" ) -type ( - Email string - Country string - Role string - - BoundingBox struct { - X1 float64 `json:"x1"` - Y1 float64 `json:"y1"` - X2 float64 `json:"x2"` - Y2 float64 `json:"y2"` - } - - User struct { - User string `json:"user"` - Role Role `json:"role"` - Password string `json:"password,omitempty"` - Email Email `json:"email"` - Country Country `json:"country"` - Extent *BoundingBox `json:"extent"` - } -) - const ( createUserSQL = `SELECT sys_admin.create_user($1, $2, $3, $4, NULL, $5)` createUserExtentSQL = `SELECT sys_admin.create_user($1, $2, $3, $4, @@ -67,123 +40,8 @@ WHERE username = $1` ) -var errNoString = errors.New("Not a string") - -var ( - // https://stackoverflow.com/questions/201323/how-to-validate-an-email-address-using-a-regular-expression - emailRe = regexp.MustCompile( - `(?:[a-z0-9!#$%&'*+/=?^_` + "`" + - `{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_` + "`" + - `{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]` + - `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")` + - `@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?` + - `|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}` + - `(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]` + - `:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]` + - `|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])`) - errNoEmailAddress = errors.New("Not a valid email address") -) - -func (e *Email) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - if !emailRe.MatchString(s) { - return errNoEmailAddress - } - *e = Email(s) - return nil -} - -func (e Email) Value() (driver.Value, error) { - return string(e), nil -} - -func (e *Email) Scan(src interface{}) (err error) { - if s, ok := src.(string); ok { - *e = Email(s) - } else { - err = errNoString - } - return -} - -var ( - validCountries = []string{ - "AT", "BG", "DE", "HU", "HR", - "MD", "RO", "RS", "SK", "UA", - } - errNoValidCountry = errors.New("Not a valid country") -) - -func (c *Country) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - s = strings.ToUpper(s) - for _, v := range validCountries { - if v == s { - *c = Country(v) - return nil - } - } - return errNoValidCountry -} - -func (c Country) Value() (driver.Value, error) { - return string(c), nil -} - -func (c *Country) Scan(src interface{}) (err error) { - if s, ok := src.(string); ok { - *c = Country(s) - } else { - err = errNoString - } - return -} - -var ( - validRoles = []string{ - "waterway_user", - "waterway_admin", - "sys_admin", - } - errNoValidRole = errors.New("Not a valid role") -) - -func (r Role) Value() (driver.Value, error) { - return string(r), nil -} - -func (r *Role) Scan(src interface{}) (err error) { - if s, ok := src.(string); ok { - *r = Role(s) - } else { - err = errNoString - } - return -} - -func (r *Role) UnmarshalJSON(data []byte) error { - var s string - if err := json.Unmarshal(data, &s); err != nil { - return err - } - s = strings.ToLower(s) - for _, v := range validRoles { - if v == s { - *r = Role(v) - return nil - } - } - return errNoValidRole -} - func deleteUser( - input interface{}, req *http.Request, + _ interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { @@ -312,7 +170,7 @@ } func listUsers( - input interface{}, req *http.Request, + _ interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { @@ -352,7 +210,7 @@ } func listUser( - input interface{}, req *http.Request, + _ interface{}, req *http.Request, db *sql.DB, ) (jr JSONResult, err error) { diff -r 22deb76dff2c -r b1116c4ce57f docs/DEVELOPMENT.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/DEVELOPMENT.md Tue Jul 31 15:56:11 2018 +0200 @@ -0,0 +1,25 @@ +# Development + +## Backend + +You need a working [Go](https://golang.org/dl) build environment (1.10+). + +* Install dependencies + + `sh 3rdpartylibs` + +* Build + + Prerequesite: compile server + ``` + cd cmd/gemma/ + go build + cd ../../ + ``` + +* Run + Run server with `./cmd/gemma/gemma` + +## Client + +See [client/README](../client/README.md) for details. diff -r 22deb76dff2c -r b1116c4ce57f schema/install-db.sh --- a/schema/install-db.sh Tue Jul 31 15:01:10 2018 +0200 +++ b/schema/install-db.sh Tue Jul 31 15:56:11 2018 +0200 @@ -98,9 +98,8 @@ if [[ $a == "yes" ]] ; then dropdb -p "$port" "$db" for r in `psql -p $port -t -c '\du' | awk -F '|' \ - '$3 ~/waterway_user|waterway_admin|sys_admin/ \ - || $1 ~/waterway_user|waterway_admin|sys_admin/ \ - {print $1}'` + '$1 "." $3 ~ /waterway_user|waterway_admin|sys_admin/ \ + {print $1}'` do dropuser -p "$port" "$r" done