diff --git a/src/controllers/api/user.go b/src/controllers/api/user.go index 16d1bf1..56afaaf 100644 --- a/src/controllers/api/user.go +++ b/src/controllers/api/user.go @@ -25,11 +25,14 @@ func NewUserController(e *common.Environment) *UserController { return &UserController{e: e} } -func (u *UserController) UserHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - if r.Method == "POST" { +func (u *UserController) UserHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + switch r.Method { + case "POST": u.saveUserHandler(w, r) - } else if r.Method == "DELETE" { + case "DELETE": u.deleteUserHandler(w, r) + case "GET": + u.getUserHandler(w, r, p) } } @@ -308,3 +311,21 @@ func (u *UserController) deleteUserHandler(w http.ResponseWriter, r *http.Reques }).Info("User deleted") common.NewAPIResponse("User deleted", nil).WriteResponse(w, http.StatusNoContent) } + +func (u *UserController) getUserHandler(w http.ResponseWriter, r *http.Request, p httprouter.Params) { + sessionUser := models.GetUserFromContext(r) + usernameParam := p.ByName("username") + + user, err := stores.GetUserStore(u.e).GetUserByUsername(usernameParam) + if err != nil { + http.Error(w, "Error getting user from database", http.StatusInternalServerError) + return + } + + if user.Username != sessionUser.Username && !sessionUser.Can(models.ViewUsers) { + common.NewAPIResponse("Unauthorized", nil).WriteResponse(w, http.StatusUnauthorized) + return + } + + common.NewAPIResponse("", user).WriteResponse(w, http.StatusOK) +} diff --git a/src/models/deviceExpiration.go b/src/models/deviceExpiration.go index 1d89dbd..2a0e47b 100644 --- a/src/models/deviceExpiration.go +++ b/src/models/deviceExpiration.go @@ -5,6 +5,7 @@ package models import ( + "encoding/json" "time" "github.com/packet-guardian/packet-guardian/src/common" @@ -25,6 +26,24 @@ const ( UserDeviceLimitUnlimited UserDeviceLimit = 0 ) +func (ue UserExpiration) string() string { + switch ue { + case UserDeviceExpirationNever: + return "never" + case UserDeviceExpirationGlobal: + return "global" + case UserDeviceExpirationSpecific: + return "specific-datetime" + case UserDeviceExpirationDuration: + return "duration" + case UserDeviceExpirationDaily: + return "daily-time" + case UserDeviceExpirationRolling: + return "rolling-duration" + } + return "" +} + var globalDeviceExpiration *UserDeviceExpiration type UserDeviceExpiration struct { @@ -32,6 +51,16 @@ type UserDeviceExpiration struct { Value int64 // Daily and Duration, time in seconds. Specific, unix epoch } +func (ude *UserDeviceExpiration) MarshalJSON() ([]byte, error) { + return json.Marshal(&struct { + Mode string `json:"mode"` + Value int64 `json:"value"` + }{ + Mode: ude.Mode.string(), + Value: ude.Value, + }) +} + func GetGlobalDefaultExpiration(e *common.Environment) *UserDeviceExpiration { g := &UserDeviceExpiration{} // Defaults to never switch e.Config.Registration.DefaultDeviceExpirationType { diff --git a/src/models/user.go b/src/models/user.go index c2d717a..b514f8d 100644 --- a/src/models/user.go +++ b/src/models/user.go @@ -5,6 +5,7 @@ package models import ( + "encoding/json" "time" "golang.org/x/crypto/bcrypt" @@ -22,25 +23,25 @@ type UserStore interface { type User struct { e *common.Environment store UserStore - ID int - Username string - Password string - HasPassword bool + ID int `json:"-"` + Username string `json:"username"` + Password string `json:"-"` + HasPassword bool `json:"has_password"` savePassword bool - ClearPassword bool - DeviceLimit UserDeviceLimit - DeviceExpiration *UserDeviceExpiration - ValidStart time.Time - ValidEnd time.Time - ValidForever bool - CanManage bool - CanAutoreg bool + ClearPassword bool `json:"-"` + DeviceLimit UserDeviceLimit `json:"device_limit"` + DeviceExpiration *UserDeviceExpiration `json:"device_expiration"` + ValidStart time.Time `json:"-"` + ValidEnd time.Time `json:"-"` + ValidForever bool `json:"valid_forever"` + CanManage bool `json:"can_manage"` + CanAutoreg bool `json:"can_autoreg"` blacklist BlacklistItem - Rights Permission + Rights Permission `json:"-"` - UIGroup string - APIGroup string - AllowStatusAPI bool + UIGroup string `json:"-"` + APIGroup string `json:"-"` + AllowStatusAPI bool `json:"-"` } // NewUser creates a new base user @@ -83,6 +84,21 @@ func (u *User) LoadRights() { } } +func (u *User) MarshalJSON() ([]byte, error) { + type Alias User + return json.Marshal(&struct { + *Alias + ValidStart time.Time `json:"valid_start"` + ValidEnd time.Time `json:"valid_end"` + Blacklisted bool `json:"blacklisted"` + }{ + Alias: (*Alias)(u), + ValidStart: u.ValidStart.UTC(), + ValidEnd: u.ValidEnd.UTC(), + Blacklisted: u.IsBlacklisted(), + }) +} + func (u *User) IsNew() bool { return (u.ID == 0 || u.Username == "") } diff --git a/src/server/routes.go b/src/server/routes.go index e59263d..ebaff98 100644 --- a/src/server/routes.go +++ b/src/server/routes.go @@ -172,6 +172,7 @@ func apiRouter(e *common.Environment) http.Handler { userAPIController := api.NewUserController(e) r.POST("/api/user", userAPIController.UserHandler) r.DELETE("/api/user", userAPIController.UserHandler) + r.GET("/api/user/:username", userAPIController.UserHandler) statusAPIController := api.NewStatusController(e) r.GET("/api/status", statusAPIController.GetStatus)