From 43148cebf5997caa6f995dd282fe2364499493df Mon Sep 17 00:00:00 2001 From: Arminas <armisss4@gmail.com> Date: Wed, 4 Jan 2023 12:55:00 +0200 Subject: [PATCH] Revert "Merge from development branch" --- custom/js/helper.js | 28 ---- handler/routes.go | 214 ++++--------------------- handler/routes_wake_on_lan.go | 2 +- handler/session.go | 32 +--- main.go | 25 +-- model/misc.go | 1 - model/user.go | 1 - router/router.go | 6 - store/jsondb/jsondb.go | 52 +----- store/store.go | 4 +- templates/base.html | 22 +-- templates/login.html | 6 +- templates/profile.html | 124 ++++++-------- templates/users_settings.html | 294 ---------------------------------- util/config.go | 1 - util/util.go | 3 +- 16 files changed, 99 insertions(+), 716 deletions(-) delete mode 100644 templates/users_settings.html diff --git a/custom/js/helper.js b/custom/js/helper.js index f337e5d..86f6dc7 100644 --- a/custom/js/helper.js +++ b/custom/js/helper.js @@ -78,34 +78,6 @@ function renderClientList(data) { }); } -function renderUserList(data) { - $.each(data, function(index, obj) { - let clientStatusHtml = '>' - - // render user html content - let html = `<div class="col-sm-6 col-md-6 col-lg-4" id="user_${obj.username}"> - <div class="info-box"> - <div class="info-box-content"> - <div class="btn-group"> - <button type="button" class="btn btn-outline-primary btn-sm" data-toggle="modal" data-target="#modal_edit_user" data-username="${obj.username}">Edit</button> - </div> - <div class="btn-group"> - <button type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal" - data-target="#modal_remove_user" data-username="${obj.username}">Delete</button> - </div> - <hr> - <span class="info-box-text"><i class="fas fa-user"></i> ${obj.username}</span> - <span class="info-box-text"><i class="fas fa-terminal"></i> ${obj.admin? 'Administrator':'Manager'}</span> - </div> - </div> - </div>` - - // add the user html elements to the list - $('#users-list').append(html); - }); -} - - function prettyDateTime(timeStr) { const dt = new Date(timeStr); const offsetMs = dt.getTimezoneOffset() * 60 * 1000; diff --git a/handler/routes.go b/handler/routes.go index 7db2a9e..3ddbb2d 100644 --- a/handler/routes.go +++ b/handler/routes.go @@ -42,54 +42,39 @@ func LoginPage() echo.HandlerFunc { // Login for signing in handler func Login(db store.IStore) echo.HandlerFunc { return func(c echo.Context) error { - data := make(map[string]interface{}) - err := json.NewDecoder(c.Request().Body).Decode(&data) + user := new(model.User) + c.Bind(user) - if err != nil { - return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"}) - } - - username := data["username"].(string) - password := data["password"].(string) - rememberMe := data["rememberMe"].(bool) - - dbuser, err := db.GetUserByName(username) + dbuser, err := db.GetUser() if err != nil { return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot query user from DB"}) } - userCorrect := subtle.ConstantTimeCompare([]byte(username), []byte(dbuser.Username)) == 1 + userCorrect := subtle.ConstantTimeCompare([]byte(user.Username), []byte(dbuser.Username)) == 1 var passwordCorrect bool if dbuser.PasswordHash != "" { - match, err := util.VerifyHash(dbuser.PasswordHash, password) + match, err := util.VerifyHash(dbuser.PasswordHash, user.Password) if err != nil { return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot verify password"}) } passwordCorrect = match } else { - passwordCorrect = subtle.ConstantTimeCompare([]byte(password), []byte(dbuser.Password)) == 1 + passwordCorrect = subtle.ConstantTimeCompare([]byte(user.Password), []byte(dbuser.Password)) == 1 } if userCorrect && passwordCorrect { // TODO: refresh the token - ageMax := 0 - expiration := time.Now().Add(24 * time.Hour) - if rememberMe { - ageMax = 86400 - expiration.Add(144 * time.Hour) - } sess, _ := session.Get("session", c) sess.Options = &sessions.Options{ Path: util.BasePath, - MaxAge: ageMax, + MaxAge: 86400, HttpOnly: true, } // set session_token tokenUID := xid.New().String() - sess.Values["username"] = dbuser.Username - sess.Values["admin"] = dbuser.Admin + sess.Values["username"] = user.Username sess.Values["session_token"] = tokenUID sess.Save(c.Request(), c.Response()) @@ -97,7 +82,7 @@ func Login(db store.IStore) echo.HandlerFunc { cookie := new(http.Cookie) cookie.Name = "session_token" cookie.Value = tokenUID - cookie.Expires = expiration + cookie.Expires = time.Now().Add(24 * time.Hour) c.SetCookie(cookie) return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Logged in successfully"}) @@ -107,40 +92,6 @@ func Login(db store.IStore) echo.HandlerFunc { } } -// GetUsers handler return a JSON list of all users -func GetUsers(db store.IStore) echo.HandlerFunc { - return func(c echo.Context) error { - - usersList, err := db.GetUsers() - if err != nil { - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{ - false, fmt.Sprintf("Cannot get user list: %v", err), - }) - } - - return c.JSON(http.StatusOK, usersList) - } -} - -// GetUser handler returns a JSON object of single user -func GetUser(db store.IStore) echo.HandlerFunc { - return func(c echo.Context) error { - - username := c.Param("username") - - if !isAdmin(c) && (username != currentUser(c)) { - return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "Manager cannot access other user data"}) - } - - userData, err := db.GetUserByName(username) - if err != nil { - return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, "User not found"}) - } - - return c.JSON(http.StatusOK, userData) - } -} - // Logout to log a user out func Logout() echo.HandlerFunc { return func(c echo.Context) error { @@ -152,23 +103,21 @@ func Logout() echo.HandlerFunc { // LoadProfile to load user information func LoadProfile(db store.IStore) echo.HandlerFunc { return func(c echo.Context) error { + + userInfo, err := db.GetUser() + if err != nil { + log.Error("Cannot get user information: ", err) + } + return c.Render(http.StatusOK, "profile.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "profile", CurrentUser: currentUser(c)}, + "userInfo": userInfo, }) } } -// UsersSettings handler -func UsersSettings(db store.IStore) echo.HandlerFunc { - return func(c echo.Context) error { - return c.Render(http.StatusOK, "users_settings.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "users-settings", CurrentUser: currentUser(c), Admin: isAdmin(c)}, - }) - } -} - -// UpdateUser to update user information -func UpdateUser(db store.IStore) echo.HandlerFunc { +// UpdateProfile to update user information +func UpdateProfile(db store.IStore) echo.HandlerFunc { return func(c echo.Context) error { data := make(map[string]interface{}) err := json.NewDecoder(c.Request().Body).Decode(&data) @@ -179,18 +128,8 @@ func UpdateUser(db store.IStore) echo.HandlerFunc { username := data["username"].(string) password := data["password"].(string) - previousUsername := data["previous_username"].(string) - admin := data["admin"].(bool) - if !isAdmin(c) && (previousUsername != currentUser(c)) { - return c.JSON(http.StatusForbidden, jsonHTTPResponse{false, "Manager cannot access other user data"}) - } - - if !isAdmin(c) { - admin = false - } - - user, err := db.GetUserByName(previousUsername) + user, err := db.GetUser() if err != nil { return c.JSON(http.StatusNotFound, jsonHTTPResponse{false, err.Error()}) } @@ -201,13 +140,6 @@ func UpdateUser(db store.IStore) echo.HandlerFunc { user.Username = username } - if username != previousUsername { - _, err := db.GetUserByName(username) - if err == nil { - return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "This username is taken"}) - } - } - if password != "" { hash, err := util.HashPassword(password) if err != nil { @@ -215,93 +147,13 @@ func UpdateUser(db store.IStore) echo.HandlerFunc { } user.PasswordHash = hash } - user.Admin = admin - - if err := db.DeleteUser(previousUsername); err != nil { - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()}) - } - if err := db.SaveUser(user); err != nil { - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()}) - } - log.Infof("Updated user information successfully") - - if previousUsername == currentUser(c) { - setUser(c, user.Username, user.Admin) - } - - return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated user information successfully"}) - } -} - -// CreateUser to create new user -func CreateUser(db store.IStore) echo.HandlerFunc { - return func(c echo.Context) error { - data := make(map[string]interface{}) - err := json.NewDecoder(c.Request().Body).Decode(&data) - - if err != nil { - return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"}) - } - - var user model.User - username := data["username"].(string) - password := data["password"].(string) - admin := data["admin"].(bool) - - if username == "" { - return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Please provide a valid username"}) - } else { - user.Username = username - } - - { - _, err := db.GetUserByName(username) - if err == nil { - return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "This username is taken"}) - } - } - - hash, err := util.HashPassword(password) - if err != nil { - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()}) - } - user.PasswordHash = hash - - user.Admin = admin if err := db.SaveUser(user); err != nil { return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, err.Error()}) } - log.Infof("Created user successfully") + log.Infof("Updated admin user information successfully") - return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Created user successfully"}) - } -} - -// RemoveUser handler -func RemoveUser(db store.IStore) echo.HandlerFunc { - return func(c echo.Context) error { - data := make(map[string]interface{}) - err := json.NewDecoder(c.Request().Body).Decode(&data) - - if err != nil { - return c.JSON(http.StatusBadRequest, jsonHTTPResponse{false, "Bad post data"}) - } - - username := data["username"].(string) - // delete user from database - - if err := db.DeleteUser(username); err != nil { - log.Error("Cannot delete user: ", err) - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot delete user from database"}) - } - - log.Infof("Removed user: %s", username) - if username == currentUser(c) { - log.Infof("You removed yourself, killing session") - clearSession(c) - } - return c.JSON(http.StatusOK, jsonHTTPResponse{true, "User removed"}) + return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Updated admin user information successfully"}) } } @@ -317,7 +169,7 @@ func WireGuardClients(db store.IStore) echo.HandlerFunc { } return c.Render(http.StatusOK, "clients.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "", CurrentUser: currentUser(c)}, "clientDataList": clientDataList, }) } @@ -670,7 +522,7 @@ func WireGuardServer(db store.IStore) echo.HandlerFunc { } return c.Render(http.StatusOK, "server.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "wg-server", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "wg-server", CurrentUser: currentUser(c)}, "serverInterface": server.Interface, "serverKeyPair": server.KeyPair, }) @@ -738,7 +590,7 @@ func GlobalSettings(db store.IStore) echo.HandlerFunc { } return c.Render(http.StatusOK, "global_settings.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "global-settings", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "global-settings", CurrentUser: currentUser(c)}, "globalSettings": globalSettings, }) } @@ -766,7 +618,7 @@ func Status(db store.IStore) echo.HandlerFunc { wgClient, err := wgctrl.New() if err != nil { return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)}, "error": err.Error(), "devices": nil, }) @@ -775,7 +627,7 @@ func Status(db store.IStore) echo.HandlerFunc { devices, err := wgClient.Devices() if err != nil { return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)}, "error": err.Error(), "devices": nil, }) @@ -787,7 +639,7 @@ func Status(db store.IStore) echo.HandlerFunc { clients, err := db.GetClients(false) if err != nil { return c.Render(http.StatusInternalServerError, "status.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)}, "error": err.Error(), "devices": nil, }) @@ -824,7 +676,7 @@ func Status(db store.IStore) echo.HandlerFunc { } return c.Render(http.StatusOK, "status.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "status", CurrentUser: currentUser(c)}, "devices": devicesVm, "error": "", }) @@ -938,12 +790,6 @@ func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc { return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get client config"}) } - users, err := db.GetUsers() - if err != nil { - log.Error("Cannot get users config: ", err) - return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get users config"}) - } - settings, err := db.GetGlobalSettings() if err != nil { log.Error("Cannot get global settings: ", err) @@ -951,7 +797,7 @@ func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc { } // Write config file - err = util.WriteWireGuardServerConfig(tmplBox, server, clients, users, settings) + err = util.WriteWireGuardServerConfig(tmplBox, server, clients, settings) if err != nil { log.Error("Cannot apply server config: ", err) return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{ diff --git a/handler/routes_wake_on_lan.go b/handler/routes_wake_on_lan.go index 43a6186..40cd387 100644 --- a/handler/routes_wake_on_lan.go +++ b/handler/routes_wake_on_lan.go @@ -37,7 +37,7 @@ func GetWakeOnLanHosts(db store.IStore) echo.HandlerFunc { } err = c.Render(http.StatusOK, "wake_on_lan_hosts.html", map[string]interface{}{ - "baseData": model.BaseData{Active: "wake_on_lan_hosts", CurrentUser: currentUser(c), Admin: isAdmin(c)}, + "baseData": model.BaseData{Active: "wake_on_lan_hosts", CurrentUser: currentUser(c)}, "hosts": hosts, "error": "", }) diff --git a/handler/session.go b/handler/session.go index 4cede6e..9975e0d 100644 --- a/handler/session.go +++ b/handler/session.go @@ -14,24 +14,15 @@ func ValidSession(next echo.HandlerFunc) echo.HandlerFunc { if !isValidSession(c) { nextURL := c.Request().URL if nextURL != nil && c.Request().Method == http.MethodGet { - return c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf(util.BasePath+"/login?next=%s", c.Request().URL)) + return c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf(util.BasePath + "/login?next=%s", c.Request().URL)) } else { - return c.Redirect(http.StatusTemporaryRedirect, util.BasePath+"/login") + return c.Redirect(http.StatusTemporaryRedirect, util.BasePath + "/login") } } return next(c) } } -func NeedsAdmin(next echo.HandlerFunc) echo.HandlerFunc { - return func(c echo.Context) error { - if !isAdmin(c) { - return c.Redirect(http.StatusTemporaryRedirect, util.BasePath+"/") - } - return next(c) - } -} - func isValidSession(c echo.Context) bool { if util.DisableLogin { return true @@ -55,29 +46,10 @@ func currentUser(c echo.Context) string { return username } -// isAdmin to get user type: admin or manager -func isAdmin(c echo.Context) bool { - if util.DisableLogin { - return true - } - - sess, _ := session.Get("session", c) - admin := fmt.Sprintf("%t", sess.Values["admin"]) - return admin == "true" -} - -func setUser(c echo.Context, username string, admin bool) { - sess, _ := session.Get("session", c) - sess.Values["username"] = username - sess.Values["admin"] = admin - sess.Save(c.Request(), c.Response()) -} - // clearSession to remove current session func clearSession(c echo.Context) { sess, _ := session.Get("session", c) sess.Values["username"] = "" - sess.Values["admin"] = false sess.Values["session_token"] = "" sess.Save(c.Request(), c.Response()) } diff --git a/main.go b/main.go index aefc0bb..3f0cd13 100644 --- a/main.go +++ b/main.go @@ -137,12 +137,7 @@ func main() { app.POST(util.BasePath+"/login", handler.Login(db)) app.GET(util.BasePath+"/logout", handler.Logout(), handler.ValidSession) app.GET(util.BasePath+"/profile", handler.LoadProfile(db), handler.ValidSession) - app.GET(util.BasePath+"/users-settings", handler.UsersSettings(db), handler.ValidSession, handler.NeedsAdmin) - app.POST(util.BasePath+"/update-user", handler.UpdateUser(db), handler.ValidSession) - app.POST(util.BasePath+"/create-user", handler.CreateUser(db), handler.ValidSession, handler.NeedsAdmin) - app.POST(util.BasePath+"/remove-user", handler.RemoveUser(db), handler.ValidSession, handler.NeedsAdmin) - app.GET(util.BasePath+"/getusers", handler.GetUsers(db), handler.ValidSession, handler.NeedsAdmin) - app.GET(util.BasePath+"/api/user/:username", handler.GetUser(db), handler.ValidSession) + app.POST(util.BasePath+"/profile", handler.UpdateProfile(db), handler.ValidSession) } var sendmail emailer.Emailer @@ -159,12 +154,11 @@ func main() { app.POST(util.BasePath+"/client/set-status", handler.SetClientStatus(db), handler.ValidSession, handler.ContentTypeJson) app.POST(util.BasePath+"/remove-client", handler.RemoveClient(db), handler.ValidSession, handler.ContentTypeJson) app.GET(util.BasePath+"/download", handler.DownloadClient(db), handler.ValidSession) - app.GET(util.BasePath+"/wg-server", handler.WireGuardServer(db), handler.ValidSession, handler.NeedsAdmin) - app.POST(util.BasePath+"/wg-server/interfaces", handler.WireGuardServerInterfaces(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) - app.POST(util.BasePath+"/wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) - app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession, handler.NeedsAdmin) - - app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson, handler.NeedsAdmin) + app.GET(util.BasePath+"/wg-server", handler.WireGuardServer(db), handler.ValidSession) + app.POST(util.BasePath+"/wg-server/interfaces", handler.WireGuardServerInterfaces(db), handler.ValidSession, handler.ContentTypeJson) + app.POST(util.BasePath+"/wg-server/keypair", handler.WireGuardServerKeyPair(db), handler.ValidSession, handler.ContentTypeJson) + app.GET(util.BasePath+"/global-settings", handler.GlobalSettings(db), handler.ValidSession) + app.POST(util.BasePath+"/global-settings", handler.GlobalSettingSubmit(db), handler.ValidSession, handler.ContentTypeJson) app.GET(util.BasePath+"/status", handler.Status(db), handler.ValidSession) app.GET(util.BasePath+"/api/clients", handler.GetClients(db), handler.ValidSession) app.GET(util.BasePath+"/api/client/:id", handler.GetClient(db), handler.ValidSession) @@ -203,13 +197,8 @@ func initServerConfig(db store.IStore, tmplBox *rice.Box) { log.Fatalf("Cannot get client config: ", err) } - users, err := db.GetUsers() - if err != nil { - log.Fatalf("Cannot get user config: ", err) - } - // write config file - err = util.WriteWireGuardServerConfig(tmplBox, server, clients, users, settings) + err = util.WriteWireGuardServerConfig(tmplBox, server, clients, settings) if err != nil { log.Fatalf("Cannot create server config: ", err) } diff --git a/model/misc.go b/model/misc.go index d8f2cf5..12d6906 100644 --- a/model/misc.go +++ b/model/misc.go @@ -10,5 +10,4 @@ type Interface struct { type BaseData struct { Active string CurrentUser string - Admin bool } diff --git a/model/user.go b/model/user.go index 71f4d13..711ebd1 100644 --- a/model/user.go +++ b/model/user.go @@ -6,5 +6,4 @@ type User struct { Password string `json:"password"` // PasswordHash takes precedence over Password. PasswordHash string `json:"password_hash"` - Admin bool `json:"admin"` } diff --git a/router/router.go b/router/router.go index f262243..0f9facc 100644 --- a/router/router.go +++ b/router/router.go @@ -83,11 +83,6 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec log.Fatal(err) } - tmplUsersSettingsString, err := tmplBox.String("users_settings.html") - if err != nil { - log.Fatal(err) - } - tmplStatusString, err := tmplBox.String("status.html") if err != nil { log.Fatal(err) @@ -108,7 +103,6 @@ func New(tmplBox *rice.Box, extraData map[string]string, secret []byte) *echo.Ec templates["clients.html"] = template.Must(template.New("clients").Funcs(funcs).Parse(tmplBaseString + tmplClientsString)) templates["server.html"] = template.Must(template.New("server").Funcs(funcs).Parse(tmplBaseString + tmplServerString)) templates["global_settings.html"] = template.Must(template.New("global_settings").Funcs(funcs).Parse(tmplBaseString + tmplGlobalSettingsString)) - templates["users_settings.html"] = template.Must(template.New("users_settings").Funcs(funcs).Parse(tmplBaseString + tmplUsersSettingsString)) templates["status.html"] = template.Must(template.New("status").Funcs(funcs).Parse(tmplBaseString + tmplStatusString)) templates["wake_on_lan_hosts.html"] = template.Must(template.New("wake_on_lan_hosts").Funcs(funcs).Parse(tmplBaseString + tmplWakeOnLanHostsString)) diff --git a/store/jsondb/jsondb.go b/store/jsondb/jsondb.go index e6ebfb2..f39a452 100644 --- a/store/jsondb/jsondb.go +++ b/store/jsondb/jsondb.go @@ -42,7 +42,7 @@ func (o *JsonDB) Init() error { var serverInterfacePath string = path.Join(serverPath, "interfaces.json") var serverKeyPairPath string = path.Join(serverPath, "keypair.json") var globalSettingPath string = path.Join(serverPath, "global_settings.json") - var userPath string = path.Join(o.dbPath, "users") + var userPath string = path.Join(serverPath, "users.json") // create directories if they do not exist if _, err := os.Stat(clientPath); os.IsNotExist(err) { os.MkdirAll(clientPath, os.ModePerm) @@ -53,9 +53,6 @@ func (o *JsonDB) Init() error { if _, err := os.Stat(wakeOnLanHostsPath); os.IsNotExist(err) { os.MkdirAll(wakeOnLanHostsPath, os.ModePerm) } - if _, err := os.Stat(userPath); os.IsNotExist(err) { - os.MkdirAll(userPath, os.ModePerm) - } // server's interface if _, err := os.Stat(serverInterfacePath); os.IsNotExist(err) { @@ -106,11 +103,9 @@ func (o *JsonDB) Init() error { } // user info - results, err := o.conn.ReadAll("users") - if err != nil || len(results) < 1 { + if _, err := os.Stat(userPath); os.IsNotExist(err) { user := new(model.User) user.Username = util.LookupEnvOrString(util.UsernameEnvVar, util.DefaultUsername) - user.Admin = util.DefaultIsAdmin user.PasswordHash = util.LookupEnvOrString(util.PasswordHashEnvVar, "") if user.PasswordHash == "" { plaintext := util.LookupEnvOrString(util.PasswordEnvVar, util.DefaultPassword) @@ -120,7 +115,7 @@ func (o *JsonDB) Init() error { } user.PasswordHash = hash } - o.conn.Write("users", user.Username, user) + o.conn.Write("server", "users", user) } return nil @@ -132,44 +127,9 @@ func (o *JsonDB) GetUser() (model.User, error) { return user, o.conn.Read("server", "users", &user) } -// GetUsers func to get all users from the database -func (o *JsonDB) GetUsers() ([]model.User, error) { - var users []model.User - results, err := o.conn.ReadAll("users") - if err != nil { - return users, err - } - for _, i := range results { - user := model.User{} - - if err := json.Unmarshal([]byte(i), &user); err != nil { - return users, fmt.Errorf("cannot decode user json structure: %v", err) - } - users = append(users, user) - - } - return users, err -} - -// GetUserByName func to get single user from the database -func (o *JsonDB) GetUserByName(username string) (model.User, error) { - user := model.User{} - - if err := o.conn.Read("users", username, &user); err != nil { - return user, err - } - - return user, nil -} - -// SaveUser func to save user in the database +// SaveUser func to user info to the database func (o *JsonDB) SaveUser(user model.User) error { - return o.conn.Write("users", user.Username, user) -} - -// DeleteUser func to remove user from the database -func (o *JsonDB) DeleteUser(username string) error { - return o.conn.Delete("users", username) + return o.conn.Write("server", "users", user) } // GetGlobalSettings func to query global settings from the database @@ -253,7 +213,7 @@ func (o *JsonDB) GetClientByID(clientID string, qrCodeSettings model.QRCodeSetti server, _ := o.GetServer() globalSettings, _ := o.GetGlobalSettings() client := client - if !qrCodeSettings.IncludeDNS { + if !qrCodeSettings.IncludeDNS{ globalSettings.DNSServers = []string{} } if !qrCodeSettings.IncludeMTU { diff --git a/store/store.go b/store/store.go index 166bc3d..86d6224 100644 --- a/store/store.go +++ b/store/store.go @@ -6,10 +6,8 @@ import ( type IStore interface { Init() error - GetUsers() ([]model.User, error) - GetUserByName(username string) (model.User, error) + GetUser() (model.User, error) SaveUser(user model.User) error - DeleteUser(username string) error GetGlobalSettings() (model.GlobalSetting, error) GetServer() (model.Server, error) GetClients(hasQRCode bool) ([]model.ClientData, error) diff --git a/templates/base.html b/templates/base.html index 227e35d..fd337a7 100644 --- a/templates/base.html +++ b/templates/base.html @@ -88,13 +88,7 @@ </div> <div class="info"> {{if .baseData.CurrentUser}} - - {{if .baseData.Admin}} - <a href="{{.basePath}}/profile" class="d-block">Administrator: {{.baseData.CurrentUser}}</a> - {{else}} - <a href="{{.basePath}}/profile" class="d-block">Manager: {{.baseData.CurrentUser}}</a> - {{end}} - + <a href="{{.basePath}}/profile" class="d-block">{{.baseData.CurrentUser}}</a> {{else}} <a href="#" class="d-block">Administrator</a> {{end}} @@ -113,8 +107,6 @@ </p> </a> </li> - - {{if .baseData.Admin}} <li class="nav-item"> <a href="{{.basePath}}/wg-server" class="nav-link {{if eq .baseData.Active "wg-server" }}active{{end}}"> <i class="nav-icon fas fa-server"></i> @@ -123,8 +115,6 @@ </p> </a> </li> - - <li class="nav-header">SETTINGS</li> <li class="nav-item"> <a href="{{.basePath}}/global-settings" class="nav-link {{if eq .baseData.Active "global-settings" }}active{{end}}"> @@ -134,16 +124,6 @@ </p> </a> </li> - <li class="nav-item"> - <a href="{{.basePath}}/users-settings" class="nav-link {{if eq .baseData.Active "users-settings" }}active{{end}}"> - <i class="nav-icon fas fa-cog"></i> - <p> - Users Settings - </p> - </a> - </li> - {{end}} - <li class="nav-header">UTILITIES</li> <li class="nav-item"> <a href="{{.basePath}}/status" class="nav-link {{if eq .baseData.Active "status" }}active{{end}}"> diff --git a/templates/login.html b/templates/login.html index db0ba24..c75aa39 100644 --- a/templates/login.html +++ b/templates/login.html @@ -99,11 +99,7 @@ $("#btn_login").click(function () { const username = $("#username").val(); const password = $("#password").val(); - let rememberMe = false; - if ($("#remember").is(':checked')){ - rememberMe = true; - } - const data = {"username": username, "password": password, "rememberMe": rememberMe} + const data = {"username": username, "password": password} $.ajax({ cache: false, diff --git a/templates/profile.html b/templates/profile.html index fa80157..c2d3b95 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -31,7 +31,7 @@ Profile <div class="form-group"> <label for="username" class="control-label">Username</label> <input type="text" class="form-control" name="username" id="username" - value=""> + value="{{ .userInfo.Username }}"> </div> <div class="form-group"> <label for="password" class="control-label">Password</label> @@ -55,82 +55,56 @@ Profile {{ define "bottom_js"}} <script> - { - var previous_username; - var admin; - } - $(document).ready(function () { - $.ajax({ - cache: false, - method: 'GET', - url: '{{.basePath}}/api/user/{{.baseData.CurrentUser}}', - dataType: 'json', - contentType: "application/json", - success: function (resp) { - const user = resp; - $("#username").val(user.username); - previous_username = user.username; - admin = user.admin; - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); + function updateUserInfo() { + const username = $("#username").val(); + const password = $("#password").val(); + const data = {"username": username, "password": password}; + $.ajax({ + cache: false, + method: 'POST', + url: '{{.basePath}}/profile', + dataType: 'json', + contentType: "application/json", + data: JSON.stringify(data), + success: function (data) { + toastr.success("Updated admin user information successfully"); + }, + error: function (jqXHR, exception) { + const responseJson = jQuery.parseJSON(jqXHR.responseText); + toastr.error(responseJson['message']); + } }); + } - - function updateUserInfo() { - const username = $("#username").val(); - const password = $("#password").val(); - const data = {"username": username, "password": password, "previous_username": previous_username, "admin":admin}; - $.ajax({ - cache: false, - method: 'POST', - url: '{{.basePath}}/update-user', - dataType: 'json', - contentType: "application/json", - data: JSON.stringify(data), - success: function (data) { - toastr.success("Updated user information successfully"); - location.reload(); - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); - } - - $(document).ready(function () { - $.validator.setDefaults({ - submitHandler: function () { - updateUserInfo(); - } - }); - $("#frm_profile").validate({ - rules: { - username: { - required: true - } - }, - messages: { - username: { - required: "Please enter a username", - } - }, - errorElement: 'span', - errorPlacement: function (error, element) { - error.addClass('invalid-feedback'); - element.closest('.form-group').append(error); - }, - highlight: function (element, errorClass, validClass) { - $(element).addClass('is-invalid'); - }, - unhighlight: function (element, errorClass, validClass) { - $(element).removeClass('is-invalid'); - } - }); + $(document).ready(function () { + $.validator.setDefaults({ + submitHandler: function () { + updateUserInfo(); + } }); + $("#frm_profile").validate({ + rules: { + username: { + required: true + } + }, + messages: { + username: { + required: "Please enter a username", + } + }, + errorElement: 'span', + errorPlacement: function (error, element) { + error.addClass('invalid-feedback'); + element.closest('.form-group').append(error); + }, + highlight: function (element, errorClass, validClass) { + $(element).addClass('is-invalid'); + }, + unhighlight: function (element, errorClass, validClass) { + $(element).removeClass('is-invalid'); + } + }); + }); </script> {{ end }} diff --git a/templates/users_settings.html b/templates/users_settings.html deleted file mode 100644 index 05d8878..0000000 --- a/templates/users_settings.html +++ /dev/null @@ -1,294 +0,0 @@ -{{define "title"}} -Users Settings -{{end}} - -{{define "top_css"}} -{{end}} - -{{define "username"}} -{{ .username }} -{{end}} - -{{define "page_title"}} -Users Settings -{{end}} - -{{define "page_content"}} -<section class="content"> - <div class="container-fluid"> - <div class="row" id="users-list"> - </div> - </div> -</section> - -<div class="modal fade" id="modal_edit_user"> - <div class="modal-dialog"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title">Edit User</h4> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - </div> - <form name="frm_edit_user" id="frm_edit_user"> - <div class="modal-body"> - <div class="form-group" style="display:none"> - <input type="text" style="display:none" class="form-control" id="_previous_user_name" - name="_previous_user_name"> - </div> - <div class="form-group"> - <label for="_user_name" class="control-label">Name</label> - <input type="text" class="form-control" id="_user_name" name="_user_name"> - </div> - <div class="form-group"> - <label for="_user_password" class="control-label">Password</label> - <input type="text" class="form-control" id="_user_password" name="_user_password" value="" - placeholder="Leave empty to keep the password unchanged"> - </div> - <div class="form-group"> - <div class="icheck-primary d-inline"> - <input type="checkbox" id="_admin"> - <label for="_admin"> - Admin - </label> - </div> - </div> - - </div> - <div class="modal-footer justify-content-between"> - <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button> - <button type="submit" class="btn btn-success">Save</button> - </div> - </form> - </div> - <!-- /.modal-content --> - </div> - <!-- /.modal-dialog --> -</div> -<!-- /.modal --> - -<div class="modal fade" id="modal_remove_user"> - <div class="modal-dialog"> - <div class="modal-content bg-danger"> - <div class="modal-header"> - <h4 class="modal-title">Remove</h4> - <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <span aria-hidden="true">×</span> - </button> - </div> - <div class="modal-body"> - </div> - <div class="modal-footer justify-content-between"> - <button type="button" class="btn btn-outline-dark" data-dismiss="modal">Cancel</button> - <button type="button" class="btn btn-outline-dark" id="remove_user_confirm">Apply</button> - </div> - </div> - <!-- /.modal-content --> - </div> - <!-- /.modal-dialog --> -</div> -<!-- /.modal --> -{{end}} - -{{define "bottom_js"}} -<script> - function populateUsersList() { - $.ajax({ - cache: false, - method: 'GET', - url: '{{.basePath}}/getusers', - dataType: 'json', - contentType: "application/json", - success: function (data) { - renderUserList(data); - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); - } -</script> -<script> - // load user list - $(document).ready(function () { - populateUsersList(); - let newUserHtml = '<div class="col-sm-2 offset-md-4" style=" text-align: right;">' + - '<button style="" id="btn_new_user" type="button" class="btn btn-outline-primary btn-sm" ' + - 'data-toggle="modal" data-target="#modal_edit_user" data-username="">' + - '<i class="nav-icon fas fa-plus"></i> New User</button></div>'; - $('h1').parents(".row").append(newUserHtml); - }) - - // modal_remove_user modal event - $("#modal_remove_user").on('show.bs.modal', function (event) { - const button = $(event.relatedTarget); - const user_name = button.data('username'); - const modal = $(this); - modal.find('.modal-body').text("You are about to remove user " + user_name); - modal.find('#remove_user_confirm').val(user_name); - }) - - // remove_user_confirm button event - $(document).ready(function () { - $("#remove_user_confirm").click(function () { - const user_name = $(this).val(); - const data = {"username": user_name}; - $.ajax({ - cache: false, - method: 'POST', - url: '{{.basePath}}/remove-user', - dataType: 'json', - contentType: "application/json", - data: JSON.stringify(data), - success: function (data) { - $("#modal_remove_user").modal('hide'); - toastr.success('Removed user successfully'); - const divElement = document.getElementById('user_' + user_name); - divElement.style.display = "none"; - location.reload() - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); - }); - }); - - // Edit user modal event - $(document).ready(function () { - $("#modal_edit_user").on('show.bs.modal', function (event) { - let modal = $(this); - const button = $(event.relatedTarget); - const user_name = button.data('username'); - - // update user modal data - if (user_name !== "") { - $.ajax({ - cache: false, - method: 'GET', - url: '{{.basePath}}/api/user/' + user_name, - dataType: 'json', - contentType: "application/json", - success: function (resp) { - const user = resp; - - modal.find(".modal-title").text("Edit user " + user.username); - modal.find("#_user_name").val(user.username); - modal.find("#_previous_user_name").val(user.username); - modal.find("#_user_password").val(""); - modal.find("#_user_password").prop("placeholder", "Leave empty to keep the password unchanged") - modal.find("#_admin").prop("checked", user.admin); - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); - } else { - modal.find(".modal-title").text("Add new user"); - modal.find("#_user_name").val(""); - modal.find("#_previous_user_name").val(""); - modal.find("#_user_password").val(""); - modal.find("#_user_password").prop("placeholder", "") - modal.find("#_admin").prop("checked", false); - } - }); - }); - - function updateUserInfo() { - const username = $("#_user_name").val(); - const previous_username = $("#_previous_user_name").val(); - const password = $("#_user_password").val(); - let admin = false; - if ($("#_admin").is(':checked')) { - admin = true; - } - const data = { - "username": username, - "password": password, - "previous_username": previous_username, - "admin": admin - }; - - if (previous_username !== "") { - $.ajax({ - cache: false, - method: 'POST', - url: '{{.basePath}}/update-user', - dataType: 'json', - contentType: "application/json", - data: JSON.stringify(data), - success: function (data) { - toastr.success("Updated user information successfully"); - location.reload(); - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); - } else { - $.ajax({ - cache: false, - method: 'POST', - url: '{{.basePath}}/create-user', - dataType: 'json', - contentType: "application/json", - data: JSON.stringify(data), - success: function (data) { - toastr.success("Created user successfully"); - location.reload(); - }, - error: function (jqXHR, exception) { - const responseJson = jQuery.parseJSON(jqXHR.responseText); - toastr.error(responseJson['message']); - } - }); - - } - } - - $(document).ready(function () { - $.validator.setDefaults({ - submitHandler: function (form) { - updateUserInfo(); - } - }); - // Edit user form validation - $("#frm_edit_user").validate({ - rules: { - _user_name: { - required: true - }, - _user_password: { - required: function () { - return $("#_previous_user_name").val() === ""; - } - }, - }, - messages: { - _user_name: { - required: "Please enter a username" - }, - _user_password: { - required: "Please input a password" - }, - }, - errorElement: 'span', - errorPlacement: function (error, element) { - error.addClass('invalid-feedback'); - element.closest('.form-group').append(error); - }, - highlight: function (element, errorClass, validClass) { - $(element).addClass('is-invalid'); - }, - unhighlight: function (element, errorClass, validClass) { - $(element).removeClass('is-invalid'); - } - }); - // - }); -</script> -{{end}} diff --git a/util/config.go b/util/config.go index 16c182f..63044ca 100644 --- a/util/config.go +++ b/util/config.go @@ -24,7 +24,6 @@ var ( const ( DefaultUsername = "admin" DefaultPassword = "admin" - DefaultIsAdmin = true DefaultServerAddress = "10.252.1.0/24" DefaultServerPort = 51820 DefaultDNS = "1.1.1.1" diff --git a/util/util.go b/util/util.go index d3b7c14..40eb357 100644 --- a/util/util.go +++ b/util/util.go @@ -381,7 +381,7 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip } // WriteWireGuardServerConfig to write Wireguard server config. e.g. wg0.conf -func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, clientDataList []model.ClientData, usersList []model.User, globalSettings model.GlobalSetting) error { +func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, clientDataList []model.ClientData, globalSettings model.GlobalSetting) error { var tmplWireguardConf string // if set, read wg.conf template from WgConfTemplate @@ -416,7 +416,6 @@ func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, cl "serverConfig": serverConfig, "clientDataList": clientDataList, "globalSettings": globalSettings, - "usersList": usersList, } err = t.Execute(f, config)