package system import ( "encoding/json" "net/http" "strconv" "strings" "time" "github.com/jinzhu/gorm" "goji.io" "goji.io/pat" "golang.org/x/net/context" libapi "dev.sum7.eu/sum7/warehost/lib/api" liblog "dev.sum7.eu/sum7/warehost/lib/log" libpassword "dev.sum7.eu/sum7/warehost/lib/password" libsession "dev.sum7.eu/sum7/warehost/lib/session" ) //MODULNAME to get global name for the modul const MODULNAME = "system" var dbconnection *gorm.DB var log *liblog.ModulLog // BindAPI sets the routes to the api functions func BindAPI(db *gorm.DB, router *goji.Mux, prefix string) { dbconnection = db log = liblog.NewModulLog(MODULNAME) router.HandleFuncC(pat.Get(prefix+"/status"), libapi.SessionHandler(status)) router.HandleFuncC(pat.Post(prefix+"/login"), libapi.SessionHandler(login)) router.HandleFuncC(pat.Get(prefix+"/logout"), libapi.SessionHandler(LoginHandler(logout))) router.HandleFuncC(pat.Post(prefix+"/password"), libapi.SessionHandler(LoginHandler(password))) router.HandleFuncC(pat.Get(prefix+"/delete"), libapi.SessionHandler(LoginHandler(delete))) router.HandleFuncC(pat.Get(prefix+"/invite"), libapi.SessionHandler(LoginHandler(inviteList))) router.HandleFuncC(pat.Post(prefix+"/invite"), libapi.SessionHandler(LoginHandler(inviteAdd))) router.HandleFuncC(pat.Get(prefix+"/user"), libapi.SessionHandler(LoginHandler(loginList))) router.HandleFuncC(pat.Post(prefix+"/user"), libapi.SessionHandler(LoginHandler(loginAdd))) router.HandleFuncC(pat.Put(prefix+"/user/:id"), libapi.SessionHandler(LoginHandler(loginEdit))) router.HandleFuncC(pat.Delete(prefix+"/user/:id"), libapi.SessionHandler(LoginHandler(loginDelete))) router.HandleFuncC(pat.Get(prefix+"/invitor"), libapi.SessionHandler(LoginHandler(invitor))) router.HandleFuncC(pat.Put(prefix+"/invitor"), libapi.SessionHandler(LoginHandler(invitorAdminToggle))) } // Status to get Login and Server status func status(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { returndata = false logger := log.GetLog(r, "status") var result int64 dbconnection.Model(&Login{}).Count(&result) if result > 0 { returndata = true } logger.Info("done") return } // Logout current user func logout(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { sess := ctx.Value("session").(libsession.Session) libsession.SessionDestroy(w, r) logger := 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("done") returndata = true return } // Login of system func login(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { sess := ctx.Value("session").(libsession.Session) returndata = false logger := 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.StatusBadRequest) return } logger = logger.WithField("user", requestlogin.Username) var login = Login{Username: requestlogin.Username} 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 dbconnection.Model(&login).Update("LastLoginAt", time.Now()) sess.Set("login", login) logger.Info("done") } 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 password(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { sess := ctx.Value("session").(libsession.Session) login := ctx.Value("login").(*Login) returndata = false logger := 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 := 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("done") returndata = true return } //Delete of login on warehost func delete(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { sess := ctx.Value("session").(libsession.Session) login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "delete") sess.Delete("login") if err := dbconnection.Unscoped().Delete(login).Error; err != nil { logger.Warn("error detete login") returnerr = &libapi.ErrorResult{Message: "Error delete login"} return } logger.Warn("done") returndata = true return } // InviteList list all of your invites func inviteList(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "invitelist") if err := 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 } logger.Info("done") returndata = login.Invites return } // InviteAdd invite a new user to warehost func inviteAdd(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := 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 := dbconnection.Create(invite).Error; err != nil { logger.Warn("error create invite") returnerr = &libapi.ErrorResult{Message: "Username exists already"} return } logger.Info("done") returndata = true return } // LoginList list all users in system func loginList(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "loginlist") var logins []Login selectfield := "ID, mail" if login.Superadmin { selectfield = "ID, mail, superadmin" } if err := dbconnection.Select(selectfield).Find(&logins).Error; err != nil { logger.Warn("sql edit login") returnerr = &libapi.ErrorResult{Message: "Error during edit login"} return } logger.Info("done") returndata = logins return } // LoginAdd add a new Login func loginAdd(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "loginadd") if !login.Superadmin { logger.Error("no superadmin") returnerr = &libapi.ErrorResult{Message: "Error no permission to edit this invite"} return } 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 } loginObj := Login{ Username: strings.ToLower(newLogin.Username), Password: libpassword.NewHash(newLogin.Password), Active: true, } if err := dbconnection.Create(loginObj).Error; err != nil { logger.Warn("error create login") returnerr = &libapi.ErrorResult{Message: "Username exists already"} return } logger.Info("done") returndata = true return } // LoginEdit edit a login by invite or superadmin func loginEdit(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "loginedit") id, err := strconv.ParseInt(pat.Param(ctx, "id"), 10, 64) 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 } dbconnection.Where("id = ?", invitedLogin.ID).First(&invitedLogin) invite := invitedLogin.GetInvitedby(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 login"} return } if len(changeLogin.Password) > 0 { invitedLogin.Password = libpassword.NewHash(changeLogin.Password) } if login.Superadmin { invitedLogin.Username = changeLogin.Username invitedLogin.Superadmin = changeLogin.Superadmin } if err := dbconnection.Save(invitedLogin).Error; err != nil { logger.Warn("sql edit login") returnerr = &libapi.ErrorResult{Message: "Error during edit login"} return } logger.Info("done") returndata = true return } // LoginDelete delete a login by invite or superadmin func loginDelete(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "logindelete") id, err := strconv.ParseInt(pat.Param(ctx, "id"), 10, 64) 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} dbconnection.Where("id = ?", invitedLogin.ID).First(&invitedLogin) invite := invitedLogin.GetInvitedby(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 login"} return } if err := dbconnection.Unscoped().Delete(invitedLogin).Error; err != nil { logger.Warn("sql detete login") returnerr = &libapi.ErrorResult{Message: "Error during delete login"} return } logger.Info("done") returndata = true return } // Invitor get Invite of current login func invitor(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "invitor") invite := login.GetInvitedby(dbconnection) logger.Info("done") returndata = invite return } // InvitorAdminToggle toggle admin of current login func invitorAdminToggle(ctx context.Context, w http.ResponseWriter, r *http.Request) (returndata interface{}, returnerr *libapi.ErrorResult) { login := ctx.Value("login").(*Login) returndata = false logger := log.GetLog(r, "invitoradmintoggle") invite := login.GetInvitedby(dbconnection) invite.Admin = !invite.Admin dbconnection.Model(invite).Save(&invite) logger.Info("done") returndata = true return }