From 19d28047a5e794e4d566c59ad4ce094404df22c8 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Tue, 24 Sep 2024 03:56:53 +0530 Subject: [PATCH 1/4] fix: Hook status issues + other small issues during deletion and creation --- shared.go | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/shared.go b/shared.go index 2aa06f6..1b25d41 100755 --- a/shared.go +++ b/shared.go @@ -12270,7 +12270,6 @@ func HandleNewHook(resp http.ResponseWriter, request *http.Request) { resp.WriteHeader(401) resp.Write([]byte(`{"success": false, "reason": "Required fields id and name can't be empty"}`)) return - } validTypes := []string{ @@ -12292,6 +12291,35 @@ func HandleNewHook(resp http.ResponseWriter, request *http.Request) { return } + originalWorkflow, err := GetWorkflow(ctx, requestdata.Workflow) + if err != nil { + log.Printf("[WARNING] Failed getting workflow %s: %s", requestdata.Workflow, err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false, "reason": "Workflow doesn't exist"}`)) + return + } + + originalHook, err := GetHook(ctx, newId) + if err == nil { + log.Printf("[WARNING] Hook with ID %s doesn't exist", newId) + } + + if originalWorkflow.OrgId != user.ActiveOrg.Id { + log.Printf("[WARNING] User %s doesn't have access to workflow %s", user.Username, requestdata.Workflow) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + + if (user.Id != originalHook.Owner || len(user.Id) == 0) && originalHook.Id != "" { + if originalHook.OrgId != user.ActiveOrg.Id && originalHook.OrgId != "" { + log.Printf("[WARNING] User %s doesn't have access to hook %s", user.Username, newId) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + } + // Let remote endpoint handle access checks (shuffler.io) baseUrl := "https://shuffler.io" if len(os.Getenv("SHUFFLE_GCEPROJECT")) > 0 && len(os.Getenv("SHUFFLE_GCEPROJECT_LOCATION")) > 0 { @@ -12373,6 +12401,33 @@ func HandleNewHook(resp http.ResponseWriter, request *http.Request) { return } + // set the same for the workflow + workflow, err := GetWorkflow(ctx, requestdata.Workflow) + if err != nil { + log.Printf("[WARNING] Failed getting workflow %s: %s", requestdata.Workflow, err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + + // get the webhook trigger with the same id + for triggerIndex, trigger := range workflow.Triggers { + if trigger.ID == newId { + workflow.Triggers[triggerIndex].Status = "running" + log.Printf("[INFO] Changed status of trigger %s to running", newId) + break + } + } + + // update the workflow + err = SetWorkflow(ctx, *workflow, workflow.ID) + if err != nil { + log.Printf("[WARNING] Failed setting workflow %s: %s", workflow.ID, err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + log.Printf("[INFO] Set up a new hook with ID %s and environment %s", newId, hook.Environment) resp.WriteHeader(200) resp.Write([]byte(`{"success": true}`)) @@ -12466,6 +12521,24 @@ func HandleDeleteHook(resp http.ResponseWriter, request *http.Request) { return } + // find workflow and set status to stopped + workflow, err := GetWorkflow(ctx, hook.Workflows[0]) + if err != nil { + log.Printf("[WARNING] Failed getting workflow %s: %s", hook.Workflows[0], err) + resp.WriteHeader(401) + resp.Write([]byte(`{"success": false}`)) + return + } + + if len(workflow.Triggers) > 0 { + for triggerIndex, trigger := range workflow.Triggers { + if trigger.ID == fileId { + workflow.Triggers[triggerIndex].Status = "stopped" + break + } + } + } + if hook.Environment == "cloud" && project.Environment != "cloud" { log.Printf("[INFO] Should STOP cloud webhook https://shuffler.io/api/v1/hooks/webhook_%s", hook.Id) org, err := GetOrg(ctx, user.ActiveOrg.Id) From 9c8c3d7b7e220dde4e12f054584b8a06a79151ec Mon Sep 17 00:00:00 2001 From: lalitdeore Date: Tue, 24 Sep 2024 17:35:10 +0530 Subject: [PATCH 2/4] fix sso redirection issue while changine org and fix manage user's permission issue --- shared.go | 256 ++++++++++++++++++++++++++++++----------------------- structs.go | 1 + 2 files changed, 144 insertions(+), 113 deletions(-) diff --git a/shared.go b/shared.go index 88567fb..ce5fdcf 100755 --- a/shared.go +++ b/shared.go @@ -1449,6 +1449,9 @@ func HandleLogout(resp http.ResponseWriter, request *http.Request) { DeleteCache(ctx, fmt.Sprintf("session_%s", userInfo.Session)) DeleteCache(ctx, userInfo.Session) + //store user's last session so we can force sso when user's session change. + userInfo.UsersLastSession = userInfo.Session + userInfo.Session = "" userInfo.ValidatedSessionOrgs = []string{} err = SetUser(ctx, &userInfo, false) @@ -5114,6 +5117,7 @@ func HandleUpdateUser(resp http.ResponseWriter, request *http.Request) { if userInfo.ActiveOrg.Id == foundUser.ActiveOrg.Id { foundUser.Role = t.Role foundUser.Roles = []string{t.Role} + foundUser.ActiveOrg.Role = t.Role } // Getting the specific org and just updating the user in that one @@ -5126,6 +5130,7 @@ func HandleUpdateUser(resp http.ResponseWriter, request *http.Request) { if user.Id == foundUser.Id { user.Role = t.Role user.Roles = []string{t.Role} + user.ActiveOrg.Role = t.Role } users = append(users, user) @@ -10766,6 +10771,7 @@ func HandleChangeUserOrg(resp http.ResponseWriter, request *http.Request) { type ReturnData struct { OrgId string `json:"org_id" datastore:"org_id"` RegionUrl string `json:"region_url" datastore:"region_url"` + SSOTest bool `json:"sso_test"` } var tmpData ReturnData @@ -10798,7 +10804,7 @@ func HandleChangeUserOrg(resp http.ResponseWriter, request *http.Request) { } } - if user.ActiveOrg.Id == fileId { + if user.ActiveOrg.Id == fileId && tmpData.SSOTest == false { log.Printf("[WARNING] User swap to the org \"%s\" - already in the org", tmpData.OrgId) resp.WriteHeader(400) resp.Write([]byte(`{"success": false, "reason": "You are already in that organisation"}`)) @@ -10828,8 +10834,7 @@ func HandleChangeUserOrg(resp http.ResponseWriter, request *http.Request) { return } - //if org.SSOConfig.SSORequired == true && !ArrayContains(user.ValidatedSessionOrgs, tmpData.OrgId) && user.SupportAccess == false { - if org.SSOConfig.SSORequired == true && !ArrayContains(user.ValidatedSessionOrgs, tmpData.OrgId) && user.SupportAccess == false { + if (org.SSOConfig.SSORequired == true && user.UsersLastSession != user.Session && user.SupportAccess == false) || tmpData.SSOTest { baseSSOUrl := org.SSOConfig.SSOEntrypoint redirectKey := "SSO_REDIRECT" @@ -18741,41 +18746,46 @@ func HandleOpenId(resp http.ResponseWriter, request *http.Request) { } expiration := time.Now().Add(3600 * time.Second) - //if len(user.Session) == 0 { - log.Printf("[INFO] User does NOT have session - creating") - sessionToken := uuid.NewV4().String() + if len(user.Session) == 0 { + log.Printf("[INFO] User does NOT have session - creating") + sessionToken := uuid.NewV4().String() - newCookie := http.Cookie{ - Name: "session_token", - Value: sessionToken, - Expires: expiration, - Path: "/", - } + newCookie := http.Cookie{ + Name: "session_token", + Value: sessionToken, + Expires: expiration, + Path: "/", + } - if project.Environment == "cloud" { - newCookie.Domain = ".shuffler.io" - newCookie.Secure = true - newCookie.HttpOnly = true - } + if project.Environment == "cloud" { + newCookie.Domain = ".shuffler.io" + newCookie.Secure = true + newCookie.HttpOnly = true + } - http.SetCookie(resp, &newCookie) + http.SetCookie(resp, &newCookie) - newCookie.Name = "__session" - http.SetCookie(resp, &newCookie) + newCookie.Name = "__session" + http.SetCookie(resp, &newCookie) - err = SetSession(ctx, user, sessionToken) - if err != nil { - log.Printf("[WARNING] Error creating session for user: %s", err) - resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) - return - } + err = SetSession(ctx, user, sessionToken) + if err != nil { + log.Printf("[WARNING] Error creating session for user: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) + return + } - user.Session = sessionToken + user.Session = sessionToken + } user.LoginInfo = append(user.LoginInfo, LoginInfo{ IP: GetRequestIp(request), Timestamp: time.Now().Unix(), }) + + //Store users last session as new session so user don't have to go through sso again while changing org. + user.UsersLastSession = user.Session + err = SetUser(ctx, &user, false) if err != nil { log.Printf("[WARNING] Failed updating user when setting session: %s", err) @@ -18806,40 +18816,45 @@ func HandleOpenId(resp http.ResponseWriter, request *http.Request) { } expiration := time.Now().Add(3600 * time.Second) - //if len(user.Session) == 0 { - log.Printf("[INFO] User does NOT have session - creating") - sessionToken := uuid.NewV4().String() - newCookie := &http.Cookie{ - Name: "session_token", - Value: sessionToken, - Expires: expiration, - Path: "/", - } + if len(user.Session) == 0 { + log.Printf("[INFO] User does NOT have session - creating") + sessionToken := uuid.NewV4().String() + newCookie := &http.Cookie{ + Name: "session_token", + Value: sessionToken, + Expires: expiration, + Path: "/", + } - if project.Environment == "cloud" { - newCookie.Domain = ".shuffler.io" - newCookie.Secure = true - newCookie.HttpOnly = true - } + if project.Environment == "cloud" { + newCookie.Domain = ".shuffler.io" + newCookie.Secure = true + newCookie.HttpOnly = true + } - http.SetCookie(resp, newCookie) + http.SetCookie(resp, newCookie) - newCookie.Name = "__session" - http.SetCookie(resp, newCookie) + newCookie.Name = "__session" + http.SetCookie(resp, newCookie) - err = SetSession(ctx, user, sessionToken) - if err != nil { - log.Printf("[WARNING] Error creating session for user: %s", err) - resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) - return - } + err = SetSession(ctx, user, sessionToken) + if err != nil { + log.Printf("[WARNING] Error creating session for user: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) + return + } - user.Session = sessionToken + user.Session = sessionToken + } user.LoginInfo = append(user.LoginInfo, LoginInfo{ IP: GetRequestIp(request), Timestamp: time.Now().Unix(), }) + + //Store users last session as new session so user don't have to go through sso again while changing org. + user.UsersLastSession = user.Session + err = SetUser(ctx, &user, false) if err != nil { log.Printf("[WARNING] Failed updating user when setting session: %s", err) @@ -18936,6 +18951,10 @@ func HandleOpenId(resp http.ResponseWriter, request *http.Request) { } newUser.Session = sessionToken + + //Store users last session as new session so user don't have to go through sso again while changing org. + newUser.UsersLastSession = sessionToken + err = SetUser(ctx, newUser, true) if err != nil { log.Printf("[WARNING] Failed setting new user in DB: %s", err) @@ -18974,7 +18993,8 @@ func HandleSSO(resp http.ResponseWriter, request *http.Request) { } if len(backendUrl) > 0 { - redirectUrl = fmt.Sprintf("%s/workflows", backendUrl) + // redirectUrl = fmt.Sprintf("%s/workflows", backendUrl) + redirectUrl = backendUrl } if project.Environment == "cloud" { @@ -19180,46 +19200,51 @@ func HandleSSO(resp http.ResponseWriter, request *http.Request) { //log.Printf("SESSION: %s", user.Session) expiration := time.Now().Add(3600 * time.Second) - // if len(user.Session) == 0 { - log.Printf("[INFO] User does NOT have session - creating") - sessionToken := uuid.NewV4().String() - newCookie := &http.Cookie{ - Name: "session_token", - Value: sessionToken, - Expires: expiration, - Path: "/", - } + if len(user.Session) == 0 { + log.Printf("[INFO] User does NOT have session - creating") + sessionToken := uuid.NewV4().String() + newCookie := &http.Cookie{ + Name: "session_token", + Value: sessionToken, + Expires: expiration, + Path: "/", + } - if project.Environment == "cloud" { - newCookie.Domain = ".shuffler.io" - newCookie.Secure = true - newCookie.HttpOnly = true - } + if project.Environment == "cloud" { + newCookie.Domain = ".shuffler.io" + newCookie.Secure = true + newCookie.HttpOnly = true + } - http.SetCookie(resp, newCookie) + http.SetCookie(resp, newCookie) - newCookie.Name = "__session" - http.SetCookie(resp, newCookie) + newCookie.Name = "__session" + http.SetCookie(resp, newCookie) - err = SetSession(ctx, user, sessionToken) - if err != nil { - log.Printf("[WARNING] Error creating session for user: %s", err) - resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) - return - } + err = SetSession(ctx, user, sessionToken) + if err != nil { + log.Printf("[WARNING] Error creating session for user: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) + return + } - user.LoginInfo = append(user.LoginInfo, LoginInfo{ - IP: GetRequestIp(request), - Timestamp: time.Now().Unix(), - }) + user.LoginInfo = append(user.LoginInfo, LoginInfo{ + IP: GetRequestIp(request), + Timestamp: time.Now().Unix(), + }) - user.Session = sessionToken + user.Session = sessionToken + } // user.LoginInfo = append(user.LoginInfo, LoginInfo{ // IP: GetRequestIp(request), // Timestamp: time.Now().Unix(), // }) // } + + //store user's last session so don't have to go through sso again while changing org. + user.UsersLastSession = user.Session + err = SetUser(ctx, &user, false) if err != nil { log.Printf("[WARNING] Failed updating user when setting session: %s", err) @@ -19254,41 +19279,43 @@ func HandleSSO(resp http.ResponseWriter, request *http.Request) { } expiration := time.Now().Add(3600 * time.Second) - // if len(user.Session) == 0 { - log.Printf("[INFO] User does NOT have session - creating") - sessionToken := uuid.NewV4().String() - newCookie := &http.Cookie{ - Name: "session_token", - Value: sessionToken, - Expires: expiration, - Path: "/", - } + if len(user.Session) == 0 { + log.Printf("[INFO] User does NOT have session - creating") + sessionToken := uuid.NewV4().String() + newCookie := &http.Cookie{ + Name: "session_token", + Value: sessionToken, + Expires: expiration, + Path: "/", + } - if project.Environment == "cloud" { - newCookie.Domain = ".shuffler.io" - newCookie.Secure = true - newCookie.HttpOnly = true - } + if project.Environment == "cloud" { + newCookie.Domain = ".shuffler.io" + newCookie.Secure = true + newCookie.HttpOnly = true + } - http.SetCookie(resp, newCookie) + http.SetCookie(resp, newCookie) - newCookie.Name = "__session" - http.SetCookie(resp, newCookie) + newCookie.Name = "__session" + http.SetCookie(resp, newCookie) - err = SetSession(ctx, user, sessionToken) - if err != nil { - log.Printf("[WARNING] Error creating session for user: %s", err) - resp.WriteHeader(401) - resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) - return - } + err = SetSession(ctx, user, sessionToken) + if err != nil { + log.Printf("[WARNING] Error creating session for user: %s", err) + resp.WriteHeader(401) + resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Failed setting session"}`))) + return + } - user.Session = sessionToken - user.LoginInfo = append(user.LoginInfo, LoginInfo{ - IP: GetRequestIp(request), - Timestamp: time.Now().Unix(), - }) - // } + user.Session = sessionToken + user.LoginInfo = append(user.LoginInfo, LoginInfo{ + IP: GetRequestIp(request), + Timestamp: time.Now().Unix(), + }) + } + //Store user's last session so don't have to go through sso again while changing org. + user.UsersLastSession = user.Session err = SetUser(ctx, &user, false) if err != nil { log.Printf("[WARNING] Failed updating user when setting session: %s", err) @@ -19393,6 +19420,9 @@ func HandleSSO(resp http.ResponseWriter, request *http.Request) { Timestamp: time.Now().Unix(), }) + //Store user's last session so don't have to go through sso again while changing org. + newUser.UsersLastSession = sessionToken + err = SetUser(ctx, newUser, true) if err != nil { log.Printf("[WARNING] Failed setting new user in DB: %s", err) diff --git a/structs.go b/structs.go index c3f2217..a942e7b 100755 --- a/structs.go +++ b/structs.go @@ -591,6 +591,7 @@ type User struct { GeneratedUsername string `datastore:"generated_username" json:"generated_username"` SessionLogin bool `datastore:"session_login" json:"session_login"` // Whether it's a login with session or API (used to verify access) ValidatedSessionOrgs []string `datastore:"validated_session_orgs" json:"validated_session_orgs"` // Orgs that have been used in the current session for the user + UsersLastSession string `datastore:"users_last_session" json:"users_last_session"` // Starting web3 integration EthInfo EthInfo `datastore:"eth_info" json:"eth_info"` From eba846c9d7cd22530bde8ce17da124403fe4c406 Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:45:09 +0530 Subject: [PATCH 3/4] fix: giving hook starting permissions to support users --- shared.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared.go b/shared.go index deab847..efb3b43 100755 --- a/shared.go +++ b/shared.go @@ -12311,11 +12311,11 @@ func HandleNewHook(resp http.ResponseWriter, request *http.Request) { return } - if (user.Id != originalHook.Owner || len(user.Id) == 0) && originalHook.Id != "" { + if (!(user.SupportAccess || user.Id == originalHook.Owner) || len(user.Id) == 0) && originalHook.Id != "" { if originalHook.OrgId != user.ActiveOrg.Id && originalHook.OrgId != "" { - log.Printf("[WARNING] User %s doesn't have access to hook %s", user.Username, newId) + log.Printf("[WARNING] User %s (from org %s) doesn't have access to hook %s (org %s)", user.Username, user.ActiveOrg.Id, originalHook.Id, originalHook.OrgId) resp.WriteHeader(401) - resp.Write([]byte(`{"success": false}`)) + resp.Write([]byte(`{"success": false, "reason": "User doesn't have access to hook"}`)) return } } From dd26acd368c44bbfa5a373e5e5069e758ecf852d Mon Sep 17 00:00:00 2001 From: Aditya <60684641+0x0elliot@users.noreply.github.com> Date: Tue, 24 Sep 2024 18:46:03 +0530 Subject: [PATCH 4/4] fix: trimming access condition fail logs --- shared.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared.go b/shared.go index efb3b43..ae5d5c2 100755 --- a/shared.go +++ b/shared.go @@ -12313,7 +12313,7 @@ func HandleNewHook(resp http.ResponseWriter, request *http.Request) { if (!(user.SupportAccess || user.Id == originalHook.Owner) || len(user.Id) == 0) && originalHook.Id != "" { if originalHook.OrgId != user.ActiveOrg.Id && originalHook.OrgId != "" { - log.Printf("[WARNING] User %s (from org %s) doesn't have access to hook %s (org %s)", user.Username, user.ActiveOrg.Id, originalHook.Id, originalHook.OrgId) + log.Printf("[WARNING] User %s doesn't have access to hook %s", user.Username, originalHook.Id) resp.WriteHeader(401) resp.Write([]byte(`{"success": false, "reason": "User doesn't have access to hook"}`)) return