package system import ( "encoding/json" "net/http" "strconv" "strings" "time" "github.com/astaxie/session" "github.com/jinzhu/gorm" "github.com/julienschmidt/httprouter" libconfig "dev.sum7.de/sum7/warehost/config" libapi "dev.sum7.de/sum7/warehost/lib/api" log "dev.sum7.de/sum7/warehost/lib/log" libpassword "dev.sum7.de/sum7/warehost/lib/password" ) //MODULNAME to get global name for the modul const MODULNAME = "system" //API keep data in module global type API struct { config *libconfig.Config sessions *session.Manager dbconnection *gorm.DB log *log.ModulLog } // NewAPI sets the routes to the api functions func NewAPI(config *libconfig.Config, sessions *session.Manager, dbconnection *gorm.DB, router *httprouter.Router, prefix string) { api := &API{ config: config, sessions: sessions, dbconnection: dbconnection, log: log.NewModulLog(MODULNAME), } router.GET(prefix+"/status", libapi.SessionHandler(api.Status, sessions)) router.POST(prefix+"/login", libapi.SessionHandler(api.Login, sessions)) router.GET(prefix+"/logout", LoginHandler(api.Logout, sessions)) router.POST(prefix+"/password", LoginHandler(api.Password, sessions)) router.GET(prefix+"/delete", LoginHandler(api.Delete, sessions)) router.GET(prefix+"/invite", LoginHandler(api.InviteList, sessions)) router.POST(prefix+"/invite", LoginHandler(api.InviteAdd, sessions)) router.PUT(prefix+"/invite/:id", LoginHandler(api.LoginEdit, sessions)) router.DELETE(prefix+"/invite/:id", LoginHandler(api.LoginDelete, sessions)) router.GET(prefix+"/invitor", LoginHandler(api.Invitor, sessions)) router.PUT(prefix+"/invitor", LoginHandler(api.InvitorAdminToggle, sessions)) } // Status to get Login and Server status func (api *API) Status(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "status") var result int64 api.dbconnection.Model(&Login{}).Count(&result) if result > 0 { returndata = true } logger.Info("status") return } // Logout current user func (api *API) Logout(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session, _ *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { api.sessions.SessionDestroy(w, r) logger := api.log.GetLog(r, "logout") if login := sess.Get("login"); login != nil { logger = logger.WithField("user", login.(Login).Username) } sess.Delete("login") sess.Delete("profil") logger.Info("logout") returndata = true return } // Login of system func (api *API) Login(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "login") var requestlogin RequestLogin err := json.NewDecoder(r.Body).Decode(&requestlogin) if err != nil { logger.Error("fetch request") http.Error(w, err.Error(), http.StatusInternalServerError) returnerr = &libapi.ErrorResult{ Message: "Internal Request Error", } return } logger = logger.WithField("user", requestlogin.Username) var login = Login{Username: requestlogin.Username} api.dbconnection.Where("mail = ?", requestlogin.Username).First(&login) if login.ID <= 0 { logger.Warn("user not found") returnerr = &libapi.ErrorResult{Fields: []string{"username"}, Message: "User not Found"} return } if login.Active { output, _ := libpassword.Validate(login.Password, requestlogin.Password) if output { returndata = true api.dbconnection.Model(&login).Update("LastLoginAt", time.Now()) sess.Set("login", login) logger.Info("logged in") } else { logger.Warn("wrong password") returnerr = &libapi.ErrorResult{Fields: []string{"password"}, Message: "Wrong Password"} } } else { logger.Warn("not active") returnerr = &libapi.ErrorResult{Fields: []string{"active"}, Message: "Not a active User"} } return } //Password to change the password func (api *API) Password(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "password") var changePasswordRequest ChangePasswordRequest err := json.NewDecoder(r.Body).Decode(&changePasswordRequest) if err != nil { logger.Error("fetch request") http.Error(w, err.Error(), http.StatusInternalServerError) returnerr = &libapi.ErrorResult{Message: "Internal Request Error"} return } output, _ := libpassword.Validate(login.Password, changePasswordRequest.CurrentPassword) if !output { logger.Warn("wrong current password") returnerr = &libapi.ErrorResult{Fields: []string{"currentpassword"}, Message: "Wrong CurrentPassword"} return } if len(changePasswordRequest.NewPassword) < MINPASSWORDLENTH { logger.Warn("wrong new password") returnerr = &libapi.ErrorResult{Fields: []string{"newpassword"}, Message: "Wrong NewPassword"} return } login.Password = libpassword.NewHash(changePasswordRequest.NewPassword) if err := api.dbconnection.Save(login).Error; err != nil { logger.Warn("error save new password to database") returnerr = &libapi.ErrorResult{Message: "Error save new password"} return } sess.Set("login", *login) logger.Info("works") returndata = true return } //Delete of login on warehost func (api *API) Delete(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "delete") logger.Warn("login delete") sess.Delete("login") if err := api.dbconnection.Unscoped().Delete(login).Error; err != nil { logger.Warn("error detete login") returnerr = &libapi.ErrorResult{Message: "Error delete login"} return } returndata = true return } // InviteList list all of your invites func (api *API) InviteList(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "invitelist") logger.Info("list invites") if err := api.dbconnection.Model(login).Preload("Invites.Invited").First(login).Error; err != nil { logger.Warn("error load own invites") returnerr = &libapi.ErrorResult{Message: "Could not load invites!"} return } returndata = login.Invites return } // InviteAdd invite a new user to warehost func (api *API) InviteAdd(w http.ResponseWriter, r *http.Request, _ httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "inviteadd") var newLogin RequestLogin err := json.NewDecoder(r.Body).Decode(&newLogin) if err != nil { logger.Error("fetch request") http.Error(w, err.Error(), http.StatusInternalServerError) returnerr = &libapi.ErrorResult{Message: "Internal Request Error"} return } invite := &Invite{ Login: *login, Invited: Login{ Username: strings.ToLower(newLogin.Username), Password: libpassword.NewHash(newLogin.Password), Active: true, }, } if err := api.dbconnection.Create(invite).Error; err != nil { logger.Warn("error create invite") returnerr = &libapi.ErrorResult{Message: "Username exists already"} return } logger.Info("invite") returndata = true return } // LoginEdit edit a login by invite or superadmin func (api *API) LoginEdit(w http.ResponseWriter, r *http.Request, ps httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "loginedit") tmpID64, err := strconv.ParseUint(ps.ByName("id"), 10, 32) id := uint(tmpID64) if err != nil { returnerr = &libapi.ErrorResult{Message: "Error invalid input"} logger.Warn("invalid userinput, no integer") return } logger = logger.WithField("id", id) var invitedLogin = Login{ID: id} var changeLogin RequestLogin err = json.NewDecoder(r.Body).Decode(&changeLogin) if err != nil { logger.Error("fetch request") http.Error(w, err.Error(), http.StatusInternalServerError) returnerr = &libapi.ErrorResult{Message: "Internal Request Error"} return } api.dbconnection.Where("id = ?", invitedLogin.ID).First(&invitedLogin) invite := login.GetInvitedby(api.dbconnection) if !login.Superadmin && !invite.Admin && invitedLogin.CreateAt.Before(invitedLogin.LastLoginAt) { logger.Warn("no permission") returnerr = &libapi.ErrorResult{Message: "Error no permission to edit this invite"} return } if len(changeLogin.Password) > 0 { invitedLogin.Password = libpassword.NewHash(changeLogin.Password) } if login.Superadmin { invitedLogin.Username = changeLogin.Username } if err := api.dbconnection.Save(invitedLogin).Error; err != nil { logger.Warn("sql edit login") returnerr = &libapi.ErrorResult{Message: "Error during edit login"} return } logger.Info("login edit") returndata = true return } // LoginDelete delete a login by invite or superadmin func (api *API) LoginDelete(w http.ResponseWriter, r *http.Request, ps httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "logindelete") tmpID64, err := strconv.ParseUint(ps.ByName("id"), 10, 32) id := uint(tmpID64) if err != nil { returnerr = &libapi.ErrorResult{Message: "Error invalid input"} logger.Warn("invalid userinput, no integer") return } logger = logger.WithField("id", id) var invitedLogin = Login{ID: id} api.dbconnection.Where("id = ?", invitedLogin.ID).First(&invitedLogin) invite := login.GetInvitedby(api.dbconnection) if !login.Superadmin && !invite.Admin && invitedLogin.CreateAt.Before(invitedLogin.LastLoginAt) { logger.Warn("no permission") returnerr = &libapi.ErrorResult{Message: "Error no permission to delete this invite"} return } if err := api.dbconnection.Unscoped().Delete(invitedLogin).Error; err != nil { logger.Warn("sql detete login") returnerr = &libapi.ErrorResult{Message: "Error during delete login"} return } logger.Info("login deleted") returndata = true return } // Invitor get Invite of current login func (api *API) Invitor(w http.ResponseWriter, r *http.Request, ps httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "invitor") invite := login.GetInvitedby(api.dbconnection) logger.Info("show invitor") returndata = invite return } // InvitorAdmin toggle admin of current login func (api *API) InvitorAdminToggle(w http.ResponseWriter, r *http.Request, ps httprouter.Params, sess session.Session, login *Login) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := api.log.GetLog(r, "invitoradmintoggle") invite := login.GetInvitedby(api.dbconnection) invite.Admin = !invite.Admin api.dbconnection.Model(invite).Save(&invite) logger.Info("toggle saved") returndata = true return }