diff --git a/.vscode/launch.json b/.vscode/launch.json index 9666a53..0ea07b8 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "type": "go", "debugAdapter": "dlv-dap", "request": "launch", - "port": 45307, + "port": 34933, "host": "127.0.0.1", "mode": "exec", "program": "${workspaceFolder}/dist/casaos-user-service-amd64_linux_amd64_v1/build/sysroot/usr/bin/casaos-user-service" diff --git a/route/v1.go b/route/v1.go index 61dd606..40e6949 100644 --- a/route/v1.go +++ b/route/v1.go @@ -43,6 +43,8 @@ func InitRouter() *gin.Engine { r.GET("/v1/users/oidc/health", v1.OIDCHealthCheck) r.GET("/v1/users/oidc/settings", v1.GetOIDCSettings) r.POST("/v1/users/oidc/saveSettings", v1.SaveOIDCSettings) + r.GET("/v1/users/1panel/health", v1.OnePanelHealthCheck) + r.POST("/v1/users/1panel/login", v1.OnePanelLogin) v1Group := r.Group("/v1") v1Group.Use(jwt.JWT( diff --git a/route/v1/user.go b/route/v1/user.go index dbffe7c..87a31bc 100644 --- a/route/v1/user.go +++ b/route/v1/user.go @@ -53,6 +53,9 @@ var ( //authURL = "http://10.0.0.26:9000/application/o/nextzenos-oidc/" callbackURL = "http://nextzenos.local/v1/users/oidc/callback" //callbackURL = "http://172.20.60.244:8080/v1/users/oidc/callback" + onePanelServer = "http://172.20.60.244:13000" + onePanelName = "nextzen" + onePanelPassword = "Smartyourlife123@*" ) type OIDCSetting struct { @@ -122,6 +125,34 @@ var limiter = rate.NewLimiter(rate.Every(time.Minute), 5) // @Param pwd query string true "password" // @Success 200 {string} string "ok" // @Router /user/login [post] +func OnePanelLogin(c *gin.Context) { + var cred = model2.OnePanelCredentials{ + Name: onePanelName, + Password: onePanelPassword, + IgnoreCaptcha: true, + Captcha: "", + CaptchaID: "", + AuthMethod: "session", + Language: "en", + } + response, cookies, err := service.MyService.OnePanel().Login(cred, "http://172.20.60.244:13000") + if err != nil { + c.JSON(common_err.SERVICE_ERROR, + model.Result{ + Success: common_err.SERVICE_ERROR, + Message: common_err.GetMsg(common_err.SERVICE_ERROR), + }) + } + for _, cookie := range cookies { + c.SetCookie(cookie.Name, cookie.Value, 3600, "/", "", false, true) + } + c.JSON(common_err.SUCCESS, + model.Result{ + Success: common_err.SUCCESS, + Message: common_err.GetMsg(common_err.SUCCESS), + Data: response, + }) +} func PostUserLogin(c *gin.Context) { if !limiter.Allow() { c.JSON(common_err.TOO_MANY_REQUEST, @@ -502,6 +533,14 @@ func determineUserRole(isSuperuser bool) string { } return "user" } +func OnePanelHealthCheck(c *gin.Context) { + status, err := service.MyService.OnePanel().HealthCheck(onePanelServer) + if err != nil || status == "Offline" { + c.JSON(http.StatusOK, model.Result{Success: common_err.OIDC_OFFLINE, Message: common_err.GetMsg(common_err.OIDC_OFFLINE), Data: "Offline"}) + return + } + c.JSON(http.StatusOK, model.Result{Success: common_err.OIDC_LIVE, Message: common_err.GetMsg(common_err.OIDC_LIVE), Data: "Live"}) +} func hashPassword() string { generatePassword, err := randString(16) diff --git a/service/1panel.go b/service/1panel.go new file mode 100644 index 0000000..b062f70 --- /dev/null +++ b/service/1panel.go @@ -0,0 +1,93 @@ +package service + +import ( + "bytes" + "encoding/json" + "fmt" + "log" + "net/http" + + model2 "github.com/KaySar12/NextZen-UserService/service/model" +) + +type OnePanelService interface { + Login(m model2.OnePanelCredentials, baseURL string) (model2.LoginResponse, []*http.Cookie, error) + Logout(m model2.OnePanelCredentials, baseURL string) (model2.LogoutResponse, error) + HealthCheck(baseURL string) (string, error) +} + +var ( + prefixV1 = "/api/v1" +) + +type onePanelService struct { +} + +func (o *onePanelService) Login(m model2.OnePanelCredentials, baseURL string) (model2.LoginResponse, []*http.Cookie, error) { + path := baseURL + prefixV1 + "/auth/login" + + // Create the request body by marshaling the credentials into JSON + reqBody, err := json.Marshal(m) + if err != nil { + return model2.LoginResponse{}, []*http.Cookie{}, fmt.Errorf("error marshaling request body: %v", err) + } + + req, err := http.NewRequest("POST", path, bytes.NewReader(reqBody)) + if err != nil { + return model2.LoginResponse{}, []*http.Cookie{}, fmt.Errorf("error creating request: %v", err) + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + + // Reuse the HTTP client (consider making it a field in onePanelService) + client := &http.Client{} + resp, err := client.Do(req) + cookies := resp.Cookies() + if err != nil { + return model2.LoginResponse{}, []*http.Cookie{}, fmt.Errorf("error making request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return model2.LoginResponse{}, []*http.Cookie{}, fmt.Errorf("HTTP error: %s", resp.Status) + } + + var result model2.LoginResponse + if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { + return model2.LoginResponse{}, []*http.Cookie{}, fmt.Errorf("error decoding response: %v", err) + } + + return result, cookies, nil +} + +func (o *onePanelService) Logout(m model2.OnePanelCredentials, baseURL string) (model2.LogoutResponse, error) { + return model2.LogoutResponse{}, nil +} + +func (o *onePanelService) HealthCheck(baseURL string) (string, error) { + path := baseURL + "/health" + req, err := http.NewRequest("GET", path, nil) + if err != nil { + log.Println("Error creating health/live request:", err) + return "Offline", err + } + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return nil // Always follow redirects + }, + } + respLive, err := client.Do(req) + if err != nil { + log.Println("Error on health/live request:", err) + return "Offline", err // Exit if the request fails + } + defer respLive.Body.Close() + if respLive.StatusCode == http.StatusOK { + return "Live", nil + } + return "Offline", err +} + +func NewOnePanelService() OnePanelService { + return &onePanelService{} +} diff --git a/service/authentik.go b/service/authentik.go index 368f915..99f6e7c 100644 --- a/service/authentik.go +++ b/service/authentik.go @@ -67,7 +67,6 @@ func (a *authentikService) GetSettings() (model2.AuthentikCredentialsDBModel, er return m, nil } -// TODO SHOULD BE Migrate to NEXTZENOS func (a *authentikService) HealthCheck(baseURL string) (string, error) { // Check health/live first pathLive := baseURL + "/-/health/live/" diff --git a/service/model/o_one_panel_credentials.go b/service/model/o_one_panel_credentials.go new file mode 100644 index 0000000..a09fb34 --- /dev/null +++ b/service/model/o_one_panel_credentials.go @@ -0,0 +1,28 @@ +package model + +type OnePanelCredentials struct { + Name string `json:"name"` + Password string `json:"password"` + IgnoreCaptcha bool `json:"ignoreCaptcha"` + Captcha string `json:"captcha"` + CaptchaID string `json:"captchaID"` + AuthMethod string `json:"authMethod"` + Language string `json:"language"` +} + +type LoginResponse struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + Name string `json:"name"` + Token string `json:"token"` + MfaStatus string `json:"mfaStatus"` + } `json:"data"` +} + +type LogoutResponse struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + } `json:"data"` +} diff --git a/service/service.go b/service/service.go index 8969af8..3b883d3 100644 --- a/service/service.go +++ b/service/service.go @@ -16,6 +16,7 @@ type Repository interface { Event() EventService OMV() OMVService Authentik() AuthentikService + OnePanel() OnePanelService } func NewService(db *gorm.DB, RuntimePath string) Repository { @@ -31,6 +32,7 @@ func NewService(db *gorm.DB, RuntimePath string) Repository { event: NewEventService(db), omv: NewOMVService(), authentik: NewAuthentikService(db), + onePanel: NewOnePanelService(), } } @@ -40,8 +42,12 @@ type store struct { event EventService omv OMVService authentik AuthentikService + onePanel OnePanelService } +func (c *store) OnePanel() OnePanelService { + return c.onePanel +} func (c *store) Event() EventService { return c.event }