Merge branch 'nightly' of github.com:Shuffle/Shuffle into nightly

This commit is contained in:
Aditya
2025-07-02 20:21:56 +05:30
194 changed files with 28711 additions and 11890 deletions
+189 -101
View File
@@ -11,17 +11,18 @@ import (
"crypto/md5"
"strconv"
"os"
"io"
"log"
"fmt"
"errors"
"net/url"
"os/exec"
"net/http"
"io/ioutil"
"math/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/exec"
"net/http/httptest"
"strings"
@@ -31,11 +32,12 @@ import (
"github.com/frikky/kin-openapi/openapi2conv"
"github.com/frikky/kin-openapi/openapi3"
//"github.com/go-git/go-billy/v5"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
gitProxy "github.com/go-git/go-git/v5/plumbing/transport"
http2 "github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/go-git/go-git/v5/storage/memory"
// Random
@@ -46,7 +48,8 @@ import (
// Web
"github.com/gorilla/mux"
http2 "gopkg.in/src-d/go-git.v4/plumbing/transport/http"
//http2 "gopkg.in/src-d/go-git.v5/plumbing/transport/http"
//http2 "github.com/go-git/go-git/plumbing/transport/http"
)
// This is used to handle onprem vs offprem databases etc
@@ -59,6 +62,7 @@ var registryName = "registry.hub.docker.com"
var runningEnvironment = "onprem"
var syncUrl = "https://shuffler.io"
//var syncUrl = "http://localhost:5002"
type retStruct struct {
Success bool `json:"success"`
@@ -445,7 +449,7 @@ func checkGitProxy(cloneOptions *git.CloneOptions) *git.CloneOptions {
func createNewUser(username, password, role, apikey string, org shuffle.OrgMini) error {
// Returns false if there is an issue
// Use this for register
err := shuffle.CheckPasswordStrength(password)
err := shuffle.CheckPasswordStrength(username, password)
if err != nil {
log.Printf("[WARNING] Bad password strength: %s", err)
return err
@@ -458,8 +462,6 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini)
}
ctx := context.Background()
//users, err := FindUser(ctx context.Context, username string) ([]User, error) {
users, err := shuffle.FindUser(ctx, strings.ToLower(strings.TrimSpace(username)))
if err != nil && len(users) == 0 {
log.Printf("[WARNING] Failed getting user %s: %s", username, err)
@@ -484,7 +486,6 @@ func createNewUser(username, password, role, apikey string, org shuffle.OrgMini)
newUser.Active = true
newUser.Orgs = []string{org.Id}
// FIXME - Remove this later
if role == "admin" {
newUser.Role = "admin"
newUser.Roles = []string{"admin"}
@@ -637,7 +638,7 @@ func handleRegister(resp http.ResponseWriter, request *http.Request) {
} else {
log.Printf("[DEBUG] Successfully created the default org!")
defaultEnv := os.Getenv("ORG_ID")
defaultEnv := os.Getenv("ENVIRONMENT_NAME")
if len(defaultEnv) == 0 {
defaultEnv = "Shuffle"
log.Printf("[DEBUG] Setting default environment for org to %s", defaultEnv)
@@ -1022,6 +1023,11 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
}
}
if parsedAdmin == "true" {
userInfo.Role = "admin"
userInfo.ActiveOrg.Role = "admin"
}
chatDisabled := false
if os.Getenv("SHUFFLE_CHAT_DISABLED") == "true" {
chatDisabled = true
@@ -1084,6 +1090,7 @@ func handleInfo(resp http.ResponseWriter, request *http.Request) {
Priorities: orgPriorities,
Licensed: licensed,
ActiveApps: activatedAppIds,
Theme: userInfo.Theme,
}
returnData, err := json.Marshal(returnValue)
@@ -1844,6 +1851,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
// return
//}
log.Printf("[DEBUG] HOOKS: webhook callback: %s", request.URL.String())
if request.Method != "POST" {
request.Method = "POST"
}
@@ -1855,6 +1864,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
path := strings.Split(request.URL.String(), "/")
if len(path) < 4 {
log.Printf("[DEBUG] HOOKS: Invalid webhook path: %s", request.URL.String())
resp.WriteHeader(403)
resp.Write([]byte(`{"success": false}`))
return
@@ -1870,7 +1880,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
if location[1] == "api" {
if len(location) <= 4 {
log.Printf("[INFO] Couldn't handle location. Too short in webhook: %d", len(location))
resp.WriteHeader(401)
resp.WriteHeader(400)
resp.Write([]byte(`{"success": false}`))
return
}
@@ -1887,6 +1897,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
}
}
log.Printf("[DEBUG] HOOKS: Pre user agent check")
// Find user agent header
userAgent := request.Header.Get("User-Agent")
if strings.Contains(strings.ToLower(userAgent), "microsoftpreview") || strings.Contains(strings.ToLower(userAgent), "googlebot") {
@@ -1909,8 +1921,8 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
//log.Printf("HookID: %s", hookId)
hook, err := shuffle.GetHook(ctx, hookId)
if err != nil {
log.Printf("[WARNING] Failed getting hook %s (callback): %s", hookId, err)
resp.WriteHeader(401)
log.Printf("[WARNING] HOOKS: Failed getting hook %s (callback): %s", hookId, err)
resp.WriteHeader(400)
resp.Write([]byte(`{"success": false}`))
return
}
@@ -1922,21 +1934,21 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
//resp.WriteHeader(200)
//resp.Write([]byte(`{"success": true}`))
if hook.Status == "stopped" {
log.Printf("[WARNING] Not running %s because hook status is stopped", hook.Id)
resp.WriteHeader(401)
log.Printf("[WARNING] HOOKS: Not running %s because hook status is stopped", hook.Id)
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "The webhook isn't running. Is it running?"}`)))
return
}
if len(hook.Workflows) == 0 {
log.Printf("[DEBUG] Not running because hook isn't connected to any workflows")
resp.WriteHeader(401)
log.Printf("[DEBUG] HOOKS: Not running because hook isn't connected to any workflows")
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "No workflows are defined"}`)))
return
}
if hook.Environment == "cloud" {
log.Printf("[DEBUG] This should trigger in the cloud. Duplicate action allowed onprem.")
log.Printf("[DEBUG] HOOKS: This should trigger in the cloud. Duplicate action allowed onprem.")
}
// Check auth
@@ -1952,7 +1964,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
log.Printf("[DEBUG] Body data error: %s", err)
log.Printf("[DEBUG] HOOKS: data read error: %s", err)
resp.WriteHeader(401)
resp.Write([]byte(`{"success": false}`))
return
@@ -1993,7 +2005,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
b, err := json.Marshal(newBody)
if err != nil {
log.Printf("[ERROR] Failed newBody marshaling for webhook: %s", err)
log.Printf("[ERROR] HOOKS: Failed newBody marshaling for webhook: %s", err)
resp.WriteHeader(500)
resp.Write([]byte(`{"success": false}`))
return
@@ -2009,7 +2021,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
}
if len(hook.Start) == 0 {
log.Printf("[WARNING] No start node for hook %s - running with workflow default.", hook.Id)
log.Printf("[ERROR] HOOKS: No start node for hook %s - running with workflow default.", hook.Id)
//bodyWrapper = string(parsedBody)
}
@@ -2021,7 +2033,6 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
// OrgId: activeOrgs[0].Id,
workflowExecution, executionResp, err := handleExecution(item, workflow, newRequest, hook.OrgId)
if err == nil {
if hook.Version == "v2" {
timeout := 15
@@ -2056,6 +2067,7 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
} else {
resp.Write([]byte(fmt.Sprintf(`{"success": true, "execution_id": "%s"}`, workflowExecution.ExecutionId)))
}
return
}
@@ -2063,6 +2075,10 @@ func handleWebhookCallback(resp http.ResponseWriter, request *http.Request) {
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "%s"}`, executionResp)))
}
log.Printf("[ERROR] HOOKS: END OF FUNCTION FOR '%s'. IF this is reached, something went wrong.", hook.Id)
resp.WriteHeader(500)
resp.Write([]byte(`{"success": false, "reason": "Failed to run workflow. Check logs."}`))
}
func handlePipelineCallback(resp http.ResponseWriter, request *http.Request) {
@@ -3079,8 +3095,9 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
return
}
// FIXME: Check whether it's in use.
if user.Id != app.Owner && user.Role != "admin" {
if user.Id == app.Owner || (user.Role == "admin" && user.ActiveOrg.Id == app.ReferenceOrg) || shuffle.ArrayContains(app.Contributors, user.Id) {
log.Printf("[DEBUG] Editing app %s with user %s (%s) in org %s", test.Id, user.Username, user.Id, user.ActiveOrg.Id)
} else {
log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name)
resp.WriteHeader(403)
resp.Write([]byte(`{"success": false, "reason": "You don't have permissions to edit this app. Contact support@shuffler.io if this persists."}`))
@@ -3154,7 +3171,18 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
}
}
api.Owner = user.Id
if api.Owner == "" {
api.Owner = user.Id
}
if len(api.ReferenceOrg) == 0 {
api.ReferenceOrg = user.ActiveOrg.Id
}
if len(test.Image) > 0 {
api.SmallImage = test.Image
api.LargeImage = test.Image
}
err = shuffle.DumpApi(basePath, api)
if err != nil {
@@ -3279,6 +3307,12 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
Body: string(body),
}
if !shuffle.ArrayContains(api.Contributors, user.Id) {
api.Contributors = append(api.Contributors, user.Id)
}
shuffle.SetAppRevision(ctx, api)
log.Printf("[INFO] API LENGTH FOR %s: %d, ID: %s", api.Name, len(parsed.Body), newmd5)
// FIXME: Might cause versioning issues if we re-use the same!!
// FIXME: Need a way to track different versions of the same app properly.
@@ -3354,6 +3388,21 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s
resp.WriteHeader(200)
resp.Write([]byte(fmt.Sprintf(`{"success": true, "id": "%s"}`, api.ID)))
}
org, err := shuffle.GetOrg(ctx, user.ActiveOrg.Id)
if err != nil {
log.Printf("[ERROR] Failed getting org during image build (%s): %s", user.ActiveOrg.Id, err)
} else {
imagenames := []string{
fmt.Sprintf("%s_%s", api.Name, api.AppVersion),
fmt.Sprintf("%s_%s", api.Name, api.ID),
}
err = shuffle.DistributeAppToEnvironments(ctx, *org, imagenames)
if err != nil {
log.Printf("[ERROR] Failed distributing app to environments: %s", err)
}
}
}
// Creates an app from the app builder
@@ -3507,7 +3556,12 @@ func handleCloudJob(job shuffle.CloudSyncJob) error {
return err
}
redirectDomain := "localhost:5001"
backendPort := os.Getenv("BACKEND_PORT")
if backendPort == "" {
backendPort = "5001"
}
redirectDomain := fmt.Sprintf("localhost:%s", backendPort)
redirectUrl := fmt.Sprintf("http://%s/api/v1/triggers/outlook/register", redirectDomain)
outlookClient, _, err := shuffle.GetOutlookClient(ctx, "", hook.OauthToken, redirectUrl)
if err != nil {
@@ -3752,30 +3806,57 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
}
}
if org.SyncConfig.WorkflowBackup {
workflows, err := shuffle.GetAllWorkflowsByQuery(ctx, foundUser, 250, "")
if err != nil {
log.Printf("[ERROR] Failed getting backup workflows for org %s: %s", org.Id, err)
} else {
backupJob.Workflows = workflows
}
// Check if it's 1/20 times (600 seconds - 10 min on average)
// Only problem: May take time to sync the first time, which is annoying
// This is to ensure that we don't spam the shuffle cloud servers with a lot of data
shouldBackupData := false
randomNumber := rand.Intn(20)
if randomNumber == 0 {
shouldBackupData = true
}
if org.SyncConfig.AppBackup && len(org.Users) > 0 {
apps, err := shuffle.GetPrioritizedApps(ctx, foundUser)
if err != nil {
log.Printf("[ERROR] Failed getting backup apps for org %s: %s", org.Id, err)
} else {
backupJob.Apps = apps
// Just to prevent it from spamming large outbound requests
if shouldBackupData {
if org.SyncConfig.WorkflowBackup {
workflows, err := shuffle.GetAllWorkflowsByQuery(ctx, foundUser, 250, "")
if err != nil {
log.Printf("[ERROR] Failed getting backup workflows for org %s: %s", org.Id, err)
} else {
backupJob.Workflows = workflows
}
}
}
info, err := shuffle.GetOrgStatistics(ctx, org.Id)
if err != nil {
log.Printf("[ERROR] Failed getting org statistics backup for org %s: %s", org.Id, err)
} else {
backupJob.Stats = *info
if org.SyncConfig.AppBackup && len(org.Users) > 0 {
foundUser.ActiveOrg.Id = org.Id
apps, err := shuffle.GetPrioritizedApps(ctx, foundUser)
if err != nil {
log.Printf("[ERROR] Failed getting backup apps for org %s: %s", org.Id, err)
} else {
parsedApps := []shuffle.WorkflowApp{}
for _, app := range apps {
if len(app.Actions) == 0 {
continue
}
if !app.Generated {
continue
}
parsedApps = append(parsedApps, app)
}
backupJob.Apps = parsedApps
}
}
// Send stats once every 10 times or so..?
// For now, just send every time
info, err := shuffle.GetOrgStatistics(ctx, org.Id)
if err != nil {
log.Printf("[ERROR] Failed getting org statistics backup for org %s: %s", org.Id, err)
} else {
backupJob.Stats = *info
}
}
backupJobData, err := json.Marshal(backupJob)
@@ -3812,6 +3893,7 @@ func remoteOrgJobHandler(org shuffle.Org, interval int) error {
//log.Printf("[ERROR] Failed cloud sync job controller run for '%s': %s", respBody, err)
return err
}
return nil
}
@@ -3843,7 +3925,7 @@ func runInitEs(ctx context.Context) {
log.Printf("[INFO] Running with HTTPS proxy %s (env: HTTPS_PROXY)", httpsProxy)
}
defaultEnv := os.Getenv("ORG_ID")
defaultEnv := os.Getenv("ENVIRONMENT_NAME")
if len(defaultEnv) == 0 {
defaultEnv = "Shuffle"
log.Printf("[DEBUG] Setting default environment for org to %s", defaultEnv)
@@ -3949,6 +4031,8 @@ func runInitEs(ctx context.Context) {
time.Sleep(30 * time.Second)
}
// FIXME: This should ONLY run on one backend instance
schedules, err := shuffle.GetAllSchedules(ctx, "ALL")
if err != nil {
log.Printf("[WARNING] Failed getting schedules during service init: %s", err)
@@ -4092,7 +4176,7 @@ func runInitEs(ctx context.Context) {
}
//interval := int(org.SyncConfig.Interval)
interval := 15
interval := 30
if interval == 0 {
log.Printf("[WARNING] Skipping org %s because sync isn't set (0).", org.Id)
continue
@@ -4161,20 +4245,26 @@ func runInitEs(ctx context.Context) {
cleanupJob := func() func() {
return func() {
log.Printf("[INFO] Running schedule for cleaning up or re-running unfinished workflows in %d environments.", len(environments))
//log.Printf("[INFO] Running schedule for cleaning up or re-running unfinished workflows in %d environments.", len(environments))
backendPort := os.Getenv("BACKEND_PORT")
if backendPort == "" {
backendPort = "5001"
}
for _, environment := range environments {
// Allowed without PROXY management as it's localhost
// client := shuffle.GetExternalClient(syncUrl)
httpClient := &http.Client{}
url := fmt.Sprintf("http://localhost:5001/api/v1/environments/%s/stop", environment)
url := fmt.Sprintf("http://localhost:%s/api/v1/environments/%s/stop", backendPort, environment)
req, err := http.NewRequest(
"GET",
url,
nil,
)
// FIXME: This will stop working of the user rotates their key lol
req.Header.Add("Authorization", fmt.Sprintf(`Bearer %s`, parsedApikey))
if err != nil {
log.Printf("[ERROR] Failed CREATING environment request for %s: %s", environment, err)
@@ -4188,14 +4278,22 @@ func runInitEs(ctx context.Context) {
continue
}
respBody, err := ioutil.ReadAll(newresp.Body)
if err != nil {
log.Printf("[ERROR] Failed setting respbody %s", err)
log.Printf("[ERROR] Failed setting respbody %s for execution stop. Status: %d", err, newresp.StatusCode)
continue
}
log.Printf("[DEBUG] Successfully ran workflow cleanup request for %s. Body: %s", environment, string(respBody))
url = fmt.Sprintf("http://localhost:5001/api/v1/environments/%s/rerun", environment)
if newresp.StatusCode != 200 {
if !strings.Contains(string(respBody), "is active") {
log.Printf("[WARNING] Failed stopping runs in environment %s. Status code: %d. Body: %s", environment, newresp.StatusCode, string(respBody))
}
continue
}
url = fmt.Sprintf("http://localhost:%s/api/v1/environments/%s/rerun", backendPort, environment)
req, err = http.NewRequest(
"GET",
url,
@@ -4215,12 +4313,17 @@ func runInitEs(ctx context.Context) {
continue
}
respBody, err = ioutil.ReadAll(newresp.Body)
if err != nil {
log.Printf("[ERROR] Failed setting respbody %s", err)
continue
if newresp.StatusCode != 200 {
log.Printf("[WARNING] Failed rerunning environment %s. Status code: %d", environment, newresp.StatusCode)
}
log.Printf("[DEBUG] Successfully ran workflow RERUN request for %s. Body: %s", environment, string(respBody))
//respBody, err := ioutil.ReadAll(newresp.Body)
//if err != nil {
// log.Printf("[ERROR] Failed setting respbody %s", err)
// continue
//}
//log.Printf("[DEBUG] Ran workflow RERUN request for %s with the response. Body: %s", environment, string(respBody))
}
}
}
@@ -4313,45 +4416,16 @@ func runInitEs(ctx context.Context) {
log.Printf("[DEBUG] Skipping download of default apps as %d were found", len(workflowapps))
}
log.Printf("[INFO] Downloading OpenAPI data for search - EXTRA APPS")
apis := "https://github.com/shuffle/security-openapis"
// THis gets memory problems hahah
//apis := "https://github.com/APIs-guru/openapi-directory"
fs := memfs.New()
storer := memory.NewStorage()
cloneOptions := &git.CloneOptions{
URL: apis,
}
cloneOptions = checkGitProxy(cloneOptions)
_, err = git.Clone(storer, fs, cloneOptions)
if err != nil {
log.Printf("[ERROR] Failed loading repo %s into memory: %s", apis, err)
} else if err == nil && len(workflowapps) < 10 {
log.Printf("[INFO] Finished git clone. Looking for updates to the repo.")
dir, err := fs.ReadDir("")
if err != nil {
log.Printf("Failed reading folder: %s", err)
}
iterateOpenApiGithub(fs, dir, "", "")
log.Printf("[INFO] Finished downloading extra API samples")
} else {
log.Printf("[INFO] Skipping download of extra API samples as %d were found", len(workflowapps))
}
if os.Getenv("SHUFFLE_HEALTHCHECK_DISABLED") != "true" {
healthcheckInterval := 30
log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval)
healthcheckInterval := 60
log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats, and dashboard on /health. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval)
job := func() {
// Prepare a fake http.responsewriter
resp := httptest.NewRecorder()
request := http.Request{}
// Add the "force=true" query to the fake request
request.URL, err = url.Parse("/api/v1/health/stats?force=true")
request.URL, err = url.Parse("/api/v1/health?force=true")
if err != nil {
log.Printf("[ERROR] Failed to parse test url for healthstats: %s", err)
}
@@ -4422,7 +4496,7 @@ func handleStopCloudSync(syncUrl string, org shuffle.Org) (*shuffle.Org, error)
return &org, errors.New(fmt.Sprintf("Couldn't find any sync key to disable org %s", org.Id))
}
log.Printf("[INFO] Should run cloud sync disable for org %s with URL %s and sync key %s", org.Id, syncUrl, org.SyncConfig.Apikey)
log.Printf("[INFO] Should run cloud sync disable for org %s with URL %s", org.Id, syncUrl)
client := shuffle.GetExternalClient(syncUrl)
req, err := http.NewRequest(
@@ -4635,7 +4709,7 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
// If you want to disable cloud sync, see previous section.
if org.CloudSync {
log.Printf("[WARNING] Org %s is already syncing. Skip", org.Id)
resp.WriteHeader(401)
resp.WriteHeader(400)
resp.Write([]byte(fmt.Sprintf(`{"success": false, "reason": "Your org is already syncing. Nothing to set up."}`)))
return
}
@@ -4712,6 +4786,9 @@ func handleCloudSetup(resp http.ResponseWriter, request *http.Request) {
org.SyncConfig = shuffle.SyncConfig{
Apikey: responseData.SessionKey,
Interval: responseData.IntervalSeconds,
WorkflowBackup: true,
AppBackup: true,
}
interval := int(responseData.IntervalSeconds)
@@ -5092,8 +5169,8 @@ func initHandlers() {
// Changed from workflows/streams to streams, as appengine was messing up
// This does not increase the API counter
// Used by frontend
r.HandleFunc("/api/v1/streams", handleWorkflowQueue).Methods("POST")
r.HandleFunc("/api/v1/streams/results", handleGetStreamResults).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/streams", handleSetWorkflowExecution).Methods("POST")
r.HandleFunc("/api/v1/streams/results", handleGetWorkflowExecutionResult).Methods("POST", "OPTIONS")
// Used by orborus
r.HandleFunc("/api/v1/workflows/queue", handleGetWorkflowqueue).Methods("GET", "POST")
@@ -5104,7 +5181,7 @@ func initHandlers() {
r.HandleFunc("/api/v1/apps/{key}/execute", executeSingleAction).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/{key}/run", executeSingleAction).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/categories", shuffle.GetActiveCategories).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/apps/categories/run", shuffle.RunCategoryAction).Methods("POST", "OPTIONS")
//r.HandleFunc("/api/v1/apps/categories/run", shuffle.RunCategoryAction).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/upload", handleAppZipUpload).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/apps/{appId}/activate", activateWorkflowAppDocker).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/apps/{appId}/deactivate", activateWorkflowAppDocker).Methods("GET", "OPTIONS")
@@ -5185,6 +5262,16 @@ func initHandlers() {
r.HandleFunc("/api/v1/hooks/{key}/delete", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS")
r.HandleFunc("/api/v1/hooks/{key}", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS")
// This structure is horrendous. Needs fixing after we got the prototype up
r.HandleFunc("/api/v1/detections", shuffle.HandleListDetectionCategories).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/detections/{detectionType}/connect", shuffle.HandleDetectionAutoConnect).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/detections/{detection_type}", shuffle.HandleGetDetectionRules).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/detections/{detection_type}/selected_rules/{action}", shuffle.HandleFolderToggle).Methods("PUT", "OPTIONS")
r.HandleFunc("/api/v1/detections/{triggerId}/selected_rules", shuffle.HandleGetSelectedRules).Methods("GET", "OPTIONS")
r.HandleFunc("/api/v1/detections/{triggerId}/selected_rules/save", shuffle.HandleSaveSelectedRules).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/detections/{detection_type}/{fileId}/{action}", shuffle.HandleToggleRule).Methods("PUT", "OPTIONS")
// OpenAPI configuration
r.HandleFunc("/api/v1/verify_swagger", verifySwagger).Methods("POST", "OPTIONS")
r.HandleFunc("/api/v1/verify_openapi", verifySwagger).Methods("POST", "OPTIONS")
@@ -5327,6 +5414,7 @@ func main() {
if innerPort == "" {
log.Printf("[DEBUG] Running on %s:5001", hostname)
log.Fatal(http.ListenAndServe(":5001", nil))
os.Setenv("BACKEND_PORT", "5001")
} else {
log.Printf("[DEBUG] Running on %s:%s", hostname, innerPort)
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", innerPort), nil))