diff --git a/dist/casaos-user-service-amd64_linux_amd64_v1/build/sysroot/usr/bin/casaos-user-service b/dist/casaos-user-service-amd64_linux_amd64_v1/build/sysroot/usr/bin/casaos-user-service index 95c3a04..43c4c9c 100755 Binary files a/dist/casaos-user-service-amd64_linux_amd64_v1/build/sysroot/usr/bin/casaos-user-service and b/dist/casaos-user-service-amd64_linux_amd64_v1/build/sysroot/usr/bin/casaos-user-service differ diff --git a/dist/metadata.json b/dist/metadata.json index eeb9db6..159999f 100644 --- a/dist/metadata.json +++ b/dist/metadata.json @@ -1 +1 @@ -{"project_name":"casaos-user-service","tag":"v1.0.0","previous_tag":"","version":"1.0.1","commit":"11de9608cd1105075bc3ac12d2130eb30d3c8004","date":"2024-07-01T02:10:13.880324864+07:00","runtime":{"goos":"linux","goarch":"amd64"}} \ No newline at end of file +{"project_name":"casaos-user-service","tag":"v1.0.0","previous_tag":"","version":"1.0.1","commit":"f0d6780c126d2fd12d8c20ca59acd6759f29ce7a","date":"2024-07-03T17:38:16.266556363+07:00","runtime":{"goos":"linux","goarch":"amd64"}} \ No newline at end of file diff --git a/main.go b/main.go index 5d886bf..d6badf7 100644 --- a/main.go +++ b/main.go @@ -101,7 +101,6 @@ func main() { v1Router := route.InitRouter() v2Router := route.InitV2Router() v2DocRouter := route.InitV2DocRouter(_docHTML, _docYAML) - _, publicKey := service.MyService.User().GetKeyPair() jswkJSON, err := jwt.GenerateJwksJSON(publicKey) diff --git a/route/v1.go b/route/v1.go index 70df0a6..e0abb8b 100644 --- a/route/v1.go +++ b/route/v1.go @@ -27,11 +27,12 @@ func InitRouter() *gin.Engine { r.POST("/v1/users/register", v1.PostUserRegister) r.POST("/v1/users/login", v1.PostUserLogin) + r.POST("/v1/users/omvlogin", v1.PostOMVLogin) r.GET("/v1/users/name", v1.GetUserAllUsername) // all/name r.POST("/v1/users/refresh", v1.PostUserRefreshToken) // No short-term modifications r.GET("/v1/users/image", v1.GetUserImage) - + r.GET("/v1/users/:username", v1.GetUserInfoByUsername) r.GET("/v1/users/status", v1.GetUserStatus) // init/check v1Group := r.Group("/v1") @@ -63,7 +64,7 @@ func InitRouter() *gin.Engine { v1UsersGroup.GET("/avatar", v1.GetUserAvatar) v1UsersGroup.DELETE("/:id", v1.DeleteUser) - v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername) + // v1UsersGroup.GET("/:username", v1.GetUserInfoByUsername) v1UsersGroup.DELETE("", v1.DeleteUserAll) } } diff --git a/route/v1/user.go b/route/v1/user.go index 17888a9..8fbbe8d 100644 --- a/route/v1/user.go +++ b/route/v1/user.go @@ -1,13 +1,17 @@ package v1 import ( + "bytes" "context" "crypto/ecdsa" "encoding/base64" + "encoding/json" json2 "encoding/json" + "fmt" "image" "image/png" "io" + "io/ioutil" "log" "net/http" url2 "net/url" @@ -39,6 +43,41 @@ import ( "github.com/gin-gonic/gin" ) +type OMVLogin struct { + Response struct { + Authenticated bool `json:"authenticated"` + Username string `json:"username"` + Permissions struct { + Role string `json:"role"` + } `json:"permissions"` + SessionID string `json:"sessionid"` + } `json:"response"` + Error interface{} `json:"error"` +} +type OMVGetUser struct { + Response struct { + Name string `json:"name"` + UID int `json:"uid"` + Gid int `json:"gid"` + Comment string `json:"comment"` + Dir string `json:"dir"` + Shell string `json:"shell"` + Lastchanged string `json:"lastchanged"` + Minimum string `json:"minimum"` + Maximum string `json:"maximum"` + Warn string `json:"warn"` + Inactive string `json:"inactive"` + Expire string `json:"expire"` + Reserved string `json:"reserved"` + Groups []string `json:"groups"` + System bool `json:"system"` + Email string `json:"email"` + Disallowusermod bool `json:"disallowusermod"` + Sshpubkeys []interface{} `json:"sshpubkeys"` + } `json:"response"` + Error interface{} `json:"error"` +} + // @Summary register user // @Router /user/register/ [post] func PostUserRegister(c *gin.Context) { @@ -133,7 +172,6 @@ func PostUserLogin(c *gin.Context) { model.Result{Success: common_err.USER_NOT_EXIST_OR_PWD_INVALID, Message: common_err.GetMsg(common_err.USER_NOT_EXIST_OR_PWD_INVALID)}) return } - // clean limit limiter = rate.NewLimiter(rate.Every(time.Minute), 5) @@ -141,13 +179,13 @@ func PostUserLogin(c *gin.Context) { token := system_model.VerifyInformation{} - accessToken, err := jwt.GetAccessToken(user.Username, privateKey, user.Id) + accessToken, err := jwt.GetAccessToken(username, privateKey, user.Id) if err != nil { c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) } token.AccessToken = accessToken - refreshToken, err := jwt.GetRefreshToken(user.Username, privateKey, user.Id) + refreshToken, err := jwt.GetRefreshToken(username, privateKey, user.Id) if err != nil { c.JSON(http.StatusInternalServerError, model.Result{Success: common_err.SERVICE_ERROR, Message: err.Error()}) } @@ -168,6 +206,147 @@ func PostUserLogin(c *gin.Context) { Data: data, }) } +func PostOMVLogin(c *gin.Context) { + if !limiter.Allow() { + c.JSON(common_err.TOO_MANY_REQUEST, + model.Result{ + Success: common_err.TOO_MANY_LOGIN_REQUESTS, + Message: common_err.GetMsg(common_err.TOO_MANY_LOGIN_REQUESTS), + }) + return + } + + json := make(map[string]string) + c.ShouldBind(&json) + + username := json["username"] + + password := json["password"] + res := LoginSession(username, password) + var resData OMVLogin + err := json2.Unmarshal([]byte(res), &resData) + + if err != nil { + // Handle the error, for example, log it or return it + log.Printf("Error getting user: %v", err) + return // or handle it in a way that fits your application's error handling strategy + } + + if !resData.Response.Authenticated { + c.JSON(common_err.CLIENT_ERROR, + model.Result{Success: common_err.USER_NOT_EXIST_OR_PWD_INVALID, Message: common_err.GetMsg(common_err.USER_NOT_EXIST_OR_PWD_INVALID)}) + return + } + + getUser, err := GetOMVUser(username, resData.Response.SessionID) + + if err != nil { + // Handle the error, for example, log it or return it + log.Printf("Error getting user: %v", err) + return // or handle it in a way that fits your application's error handling strategy + } + + var userData OMVGetUser + err = json2.Unmarshal([]byte(getUser), &userData) + + if err != nil { + // Handle the error, for example, log it or return it + log.Printf("Error getting user: %v", err) + return // or handle it in a way that fits your application's error handling strategy + } + + if isEmpty(userData.Response) { + c.JSON(common_err.CLIENT_ERROR, + model.Result{ + Success: common_err.USER_NOT_EXIST_OR_PWD_INVALID, + Message: common_err.GetMsg(common_err.USER_NOT_EXIST_OR_PWD_INVALID)}) + return + } + c.SetCookie( + "sessionID", + resData.Response.SessionID, + 3600, + "/", + "", + false, + true) + c.JSON(common_err.SUCCESS, + model.Result{ + Success: common_err.SUCCESS, + Message: common_err.GetMsg(common_err.SUCCESS), + Data: userData, + }) + +} + +func isEmpty(obj interface{}) bool { + jsonData, err := json.Marshal(obj) + if err != nil && string(jsonData) == "{}" { + return true + } + return false +} + +func GetOMVUser(username string, sessionID string) (string, error) { + // Prepare the RPC request + postBody, _ := json.Marshal(map[string]interface{}{ + "service": "UserMgmt", + "method": "getUser", + "params": map[string]string{ + "name": username, + }, + }) + responseBody := bytes.NewBuffer(postBody) + + // Create HTTP request and set session ID header + req, err := http.NewRequest("POST", "http://10.0.0.4:1081/rpc.php", responseBody) + if err != nil { + return "", fmt.Errorf("error creating request: %v", err) + } + req.Header.Set("X-OPENMEDIAVAULT-SESSIONID", sessionID) // Set session ID header + + // Send the request + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return "", fmt.Errorf("error making request: %v", err) + } + defer resp.Body.Close() // Ensure the response body is closed + + // Check for HTTP errors + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("HTTP error: %s", resp.Status) + } + + // Read the response body + responseData, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("error reading response body: %v", err) + } + + return string(responseData), nil +} +func LoginSession(username string, password string) string { + postBody, _ := json.Marshal(map[string]interface{}{ + "service": "session", + "method": "login", + "params": map[string]string{ + "username": username, + "password": password, + }, + }) + responseBody := bytes.NewBuffer(postBody) + response, err := http.Post("http://10.0.0.4:1081/rpc.php", "application/json", responseBody) + if err != nil { + fmt.Print(err.Error()) + os.Exit(1) + } + responseData, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Fatal(err) + } + return string(responseData) +} // @Summary edit user head // @Produce application/json @@ -431,7 +610,7 @@ func GetUserInfoByUsername(c *gin.Context) { } user := service.MyService.User().GetUserInfoByUserName(username) if user.Id == 0 { - c.JSON(common_err.SERVICE_ERROR, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) + c.JSON(common_err.USER_NOT_EXIST, model.Result{Success: common_err.USER_NOT_EXIST, Message: common_err.GetMsg(common_err.USER_NOT_EXIST)}) return } diff --git a/service/model/o_user.go b/service/model/o_user.go index 34b080b..37d1cfb 100644 --- a/service/model/o_user.go +++ b/service/model/o_user.go @@ -11,7 +11,7 @@ package model import "time" -//Soon to be removed +// Soon to be removed type UserDBModel struct { Id int `gorm:"column:id;primary_key" json:"id"` Username string `json:"username"` diff --git a/service/omv.go b/service/omv.go new file mode 100644 index 0000000..0546a23 --- /dev/null +++ b/service/omv.go @@ -0,0 +1,87 @@ +package service + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + + "github.com/IceWhaleTech/CasaOS-UserService/service/model" +) + +type OMVService interface { + LoginSession(userName string, password string) string + Logout() + GetUser(username string) string + SetUser(m model.UserDBModel) model.UserDBModel + ApplyChange() +} +type omvService struct { +} + +// LoginSession implements OMVService. +func (o *omvService) LoginSession(userName string, password string) string { + panic("unimplemented") +} + +func LoginSession(username string, password string) string { + postBody, _ := json.Marshal(map[string]interface{}{ + "service": "session", + "method": "login", + "params": map[string]string{ + "username": username, + "password": password, + }, + }) + responseBody := bytes.NewBuffer(postBody) + response, err := http.Post("http://10.0.0.4:1081/rpc.php", "application/json", responseBody) + if err != nil { + fmt.Print(err.Error()) + os.Exit(1) + } + responseData, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Fatal(err) + } + return string(responseData) +} +func (o *omvService) Logout() { + // Implement logout logic here +} + +func (o *omvService) GetUser(username string) string { + postBody, _ := json.Marshal(map[string]interface{}{ + "service": "UserMgmt", + "method": "getUser", + "params": map[string]string{ + "name": username, + }, + }) + responseBody := bytes.NewBuffer(postBody) + response, err := http.Post("http://10.0.0.4:1081/rpc.php", "application/json", responseBody) + if err != nil { + fmt.Print(err.Error()) + os.Exit(1) + } + responseData, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Fatal(err) + } + return string(responseData) +} + +func (o *omvService) SetUser(m model.UserDBModel) model.UserDBModel { + // Implement SetUser logic here + return m // Assuming m is the modified user +} + +func (o *omvService) ApplyChange() { + // Implement ApplyChange logic here +} + +func NewOMVService() OMVService { + return &omvService{} +} diff --git a/service/service.go b/service/service.go index 8235635..1ad43f6 100644 --- a/service/service.go +++ b/service/service.go @@ -14,6 +14,7 @@ type Repository interface { User() UserService MessageBus() *message_bus.ClientWithResponses Event() EventService + OMV() OMVService } func NewService(db *gorm.DB, RuntimePath string) Repository { @@ -27,6 +28,7 @@ func NewService(db *gorm.DB, RuntimePath string) Repository { gateway: gatewayManagement, user: NewUserService(db), event: NewEventService(db), + omv: NewOMVService(), } } @@ -34,8 +36,12 @@ type store struct { gateway external.ManagementService user UserService event EventService + omv OMVService } +func (c *store) OMV() OMVService { + return c.omv +} func (c *store) Event() EventService { return c.event }