From 5ed0cfa837427f848e3d7d5871f3fe0df1a5402a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lie=20Delhaie?= Date: Tue, 14 Jun 2022 20:34:55 +0200 Subject: [PATCH] Admin endpoints --- admin/admin.go | 29 +++++ authentication/authentication.go | 7 +- database/database.go | 25 +++-- server/admin.go | 178 +++++++++++++++++++++++++++++++ server/data.go | 27 ++++- server/response.go | 21 ++++ server/server.go | 12 ++- upload/upload.go | 24 +++++ 8 files changed, 304 insertions(+), 19 deletions(-) create mode 100644 admin/admin.go create mode 100644 server/admin.go diff --git a/admin/admin.go b/admin/admin.go new file mode 100644 index 0000000..5cd58ad --- /dev/null +++ b/admin/admin.go @@ -0,0 +1,29 @@ +package admin + +import ( + "opensavecloudserver/database" + "opensavecloudserver/upload" +) + +// RemoveUser rome the user from the db and all his datas +func RemoveUser(user *database.User) error { + if err := database.RemoveAllUserGameEntries(user); err != nil { + return err + } + if err := upload.RemoveFolders(user.ID); err != nil { + return err + } + return database.RemoveUser(user) +} + +func SetAdmin(user *database.User) error { + user.Role = database.AdminRole + user.IsAdmin = true + return database.SaveUser(user) +} + +func RemoveAdminRole(user *database.User) error { + user.Role = database.UserRole + user.IsAdmin = false + return database.SaveUser(user) +} diff --git a/authentication/authentication.go b/authentication/authentication.go index ff8dcfe..2f250bd 100644 --- a/authentication/authentication.go +++ b/authentication/authentication.go @@ -16,11 +16,8 @@ type AccessToken struct { } type Registration struct { - Username string `json:"username"` - Password string `json:"password"` - Firstname string `json:"firstname"` - Lastname string `json:"lastname"` - Pronouns int `json:"pronouns"` + Username string `json:"username"` + Password string `json:"password"` } func init() { diff --git a/database/database.go b/database/database.go index 5264739..0abf8a7 100644 --- a/database/database.go +++ b/database/database.go @@ -15,7 +15,8 @@ import ( var db *gorm.DB -const adminRole string = "admin" +const AdminRole string = "admin" +const UserRole string = "user" func init() { dbConfig := config.Database() @@ -56,7 +57,7 @@ func AllUsers() ([]*User, error) { return nil, err } for _, user := range users { - if user.Role == adminRole { + if user.Role == AdminRole { user.IsAdmin = true } } @@ -70,7 +71,7 @@ func UserByUsername(username string) (*User, error) { if err != nil { return nil, err } - if user.Role == adminRole { + if user.Role == AdminRole { user.IsAdmin = true } return user, nil @@ -79,11 +80,11 @@ func UserByUsername(username string) (*User, error) { // UserById get a user func UserById(userId int) (*User, error) { var user *User - err := db.Model(User{}).Where(User{ID: userId}).First(&user).Error + err := db.Model(User{}).Where(userId).First(&user).Error if err != nil { return nil, err } - if user.Role == adminRole { + if user.Role == AdminRole { user.IsAdmin = true } return user, nil @@ -98,12 +99,24 @@ func AddUser(username string, password []byte) error { return db.Save(user).Error } +func SaveUser(user *User) error { + return db.Save(user).Error +} + +func RemoveUser(user *User) error { + return db.Delete(User{}, user.ID).Error +} + +func RemoveAllUserGameEntries(user *User) error { + return db.Delete(Game{}, Game{UserId: user.ID}).Error +} + // AddAdmin register a user and set his role to admin /*func AddAdmin(username string, password []byte) error { user := &User{ Username: username, Password: password, - Role: adminRole, + Role: AdminRole, } return db.Save(user).Error }*/ diff --git a/server/admin.go b/server/admin.go new file mode 100644 index 0000000..287697d --- /dev/null +++ b/server/admin.go @@ -0,0 +1,178 @@ +package server + +import ( + "encoding/json" + "github.com/go-chi/chi/v5" + "io" + "log" + "net/http" + "opensavecloudserver/admin" + "opensavecloudserver/authentication" + "opensavecloudserver/database" + "strconv" + "time" +) + +func AddUser(w http.ResponseWriter, r *http.Request) { + body, err := io.ReadAll(r.Body) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + userInfo := new(authentication.Registration) + err = json.Unmarshal(body, userInfo) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + err = authentication.Register(userInfo) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + user, err := database.UserByUsername(userInfo.Username) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + ok(user, w, r) +} + +func RemoveUser(w http.ResponseWriter, r *http.Request) { + queryId := chi.URLParam(r, "id") + id, err := strconv.Atoi(queryId) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + user, err := database.UserById(id) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + err = admin.RemoveUser(user) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + ok(user, w, r) +} + +func AllUsers(w http.ResponseWriter, r *http.Request) { + users, err := database.AllUsers() + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + ok(users, w, r) +} + +func User(w http.ResponseWriter, r *http.Request) { + queryId := chi.URLParam(r, "id") + id, err := strconv.Atoi(queryId) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + user, err := database.UserById(id) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + ok(user, w, r) +} + +func SetAdmin(w http.ResponseWriter, r *http.Request) { + queryId := chi.URLParam(r, "id") + id, err := strconv.Atoi(queryId) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + user, err := database.UserById(id) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + err = admin.SetAdmin(user) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + ok(user, w, r) +} + +func SetNotAdmin(w http.ResponseWriter, r *http.Request) { + queryId := chi.URLParam(r, "id") + id, err := strconv.Atoi(queryId) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + user, err := database.UserById(id) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + err = admin.RemoveAdminRole(user) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + ok(user, w, r) +} + +func ChangeUserPassword(w http.ResponseWriter, r *http.Request) { + queryId := chi.URLParam(r, "id") + userId, err := strconv.Atoi(queryId) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + body, err := io.ReadAll(r.Body) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + newPassword := new(NewPassword) + err = json.Unmarshal(body, newPassword) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + if newPassword.Password != newPassword.VerifyPassword { + badRequest("password are not the same", w, r) + return + } + err = database.ChangePassword(userId, []byte(newPassword.Password)) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + payload := &successMessage{ + Message: "Password changed", + Timestamp: time.Now(), + Status: 200, + } + ok(payload, w, r) +} diff --git a/server/data.go b/server/data.go index 72ae580..11b576b 100644 --- a/server/data.go +++ b/server/data.go @@ -81,7 +81,7 @@ func GameInfoByID(w http.ResponseWriter, r *http.Request) { } game, err := database.GameInfoById(userId, id) if err != nil { - internalServerError(w, r) + notFound(err.Error(), w, r) log.Println(err) return } @@ -293,12 +293,31 @@ func ChangePassword(w http.ResponseWriter, r *http.Request) { ok(payload, w, r) } -func AllUsers(w http.ResponseWriter, r *http.Request) { - users, err := database.AllUsers() +func RemoveGame(w http.ResponseWriter, r *http.Request) { + userId, err := userIdFromContext(r.Context()) if err != nil { internalServerError(w, r) log.Println(err) return } - ok(users, w, r) + queryId := chi.URLParam(r, "id") + id, err := strconv.Atoi(queryId) + if err != nil { + badRequest("Game ID missing or not an int", w, r) + log.Println(err) + return + } + game, err := database.GameInfoById(userId, id) + if err != nil { + notFound(err.Error(), w, r) + log.Println(err) + return + } + err = upload.RemoveGame(userId, game) + if err != nil { + internalServerError(w, r) + log.Println(err) + return + } + ok(game, w, r) } diff --git a/server/response.go b/server/response.go index d6328d5..dfd851a 100644 --- a/server/response.go +++ b/server/response.go @@ -42,6 +42,27 @@ func internalServerError(w http.ResponseWriter, r *http.Request) { } } +func notFound(message string, w http.ResponseWriter, r *http.Request) { + e := httpError{ + Status: 404, + Error: "Not Found", + Message: message, + Path: r.RequestURI, + Timestamp: time.Now(), + } + + payload, err := json.Marshal(e) + if err != nil { + log.Println(err) + } + w.Header().Add("Content-Type", "application/json") + w.WriteHeader(404) + _, err = w.Write(payload) + if err != nil { + log.Println(err) + } +} + func unauthorized(w http.ResponseWriter, r *http.Request) { e := httpError{ Status: 401, diff --git a/server/server.go b/server/server.go index 18eae88..82032f8 100644 --- a/server/server.go +++ b/server/server.go @@ -35,9 +35,6 @@ func Serve() { } r.Route("/system", func(systemRouter chi.Router) { systemRouter.Get("/information", Information) - systemRouter.Group(func(secureRouter chi.Router) { - secureRouter.Get("/users", AllUsers) - }) }) r.Route("/user", func(secureRouter chi.Router) { secureRouter.Use(authMiddleware) @@ -45,13 +42,20 @@ func Serve() { secureRouter.Post("/passwd", ChangePassword) }) r.Route("/admin", func(secureRouter chi.Router) { - secureRouter.Use(authMiddleware) secureRouter.Use(adminMiddleware) + secureRouter.Post("/user", AddUser) + secureRouter.Post("/user/passwd/{id}", ChangeUserPassword) + secureRouter.Delete("/user/{id}", RemoveUser) + secureRouter.Get("/user/{id}", User) + secureRouter.Get("/users", AllUsers) + secureRouter.Get("/user/role/admin/{id}", SetAdmin) + secureRouter.Get("/user/role/user/{id}", SetNotAdmin) }) r.Route("/game", func(secureRouter chi.Router) { secureRouter.Use(authMiddleware) secureRouter.Post("/create", CreateGame) secureRouter.Get("/all", AllGamesInformation) + secureRouter.Delete("/remove/{id}", RemoveGame) secureRouter.Get("/info/{id}", GameInfoByID) secureRouter.Post("/upload/init", AskForUpload) secureRouter.Group(func(uploadRouter chi.Router) { diff --git a/upload/upload.go b/upload/upload.go index b2be337..08225e8 100644 --- a/upload/upload.go +++ b/upload/upload.go @@ -163,6 +163,30 @@ func UnlockGame(gameId int) { delete(locks, gameId) } +// RemoveFolders remove all files of the user from storage and cache +func RemoveFolders(userId int) error { + userPath := path.Join(config.Path().Storage, strconv.Itoa(userId)) + userCache := path.Join(config.Path().Cache, strconv.Itoa(userId)) + if _, err := os.Stat(userPath); err == nil { + err := os.RemoveAll(userPath) + if err != nil { + log.Fatal(err) + } + } + if _, err := os.Stat(userCache); err == nil { + err := os.RemoveAll(userCache) + if err != nil { + log.Fatal(err) + } + } + return nil +} + +func RemoveGame(userId int, game *database.Game) error { + filePath := path.Join(config.Path().Storage, strconv.Itoa(userId), game.PathStorage) + return os.Remove(filePath) +} + // clearLocks clear lock of zombi upload func clearLocks() { mu.Lock()