From ee467daff7327f982a78b3061d1452c0588cb636 Mon Sep 17 00:00:00 2001 From: j3ssie Date: Mon, 21 Apr 2025 21:12:47 +0800 Subject: [PATCH] Fix some bugs and refactor the API server --- cmd/cloud.go | 2 +- cmd/config.go | 8 + cmd/health.go | 33 +- cmd/root.go | 1 + cmd/scan.go | 3 +- cmd/server.go | 3 +- cmd/usage.go | 2 +- core/config.go | 23 +- core/flowchart.go | 64 +++ core/module.go | 1 - core/parse.go | 3 +- core/reference.go | 7 +- core/runner.go | 17 +- core/runtime.go | 6 + core/update.go | 1 - docs/docs.go | 537 ++++++++++++++++++++ docs/swagger.json | 508 ++++++++++++++++++ docs/swagger.yaml | 323 ++++++++++++ execution/git.go | 2 +- execution/scripts.go | 2 - go.mod | 42 +- go.sum | 89 ++-- libs/options.go | 2 + libs/version.go | 2 +- server/auth.go | 11 +- server/builder.go | 30 +- server/mics.go | 15 + server/ping.go | 20 +- server/router.go | 59 ++- server/scan.go | 83 +-- server/workspace.go | 32 +- test-workflows/flow-with-params.yaml | 4 + test-workflows/sample/loop-step.yaml | 20 + test-workflows/sample/with-threadshold.yaml | 14 + test-workflows/test-module/new-params.yaml | 12 +- utils/helper.go | 37 ++ 36 files changed, 1828 insertions(+), 190 deletions(-) create mode 100644 core/flowchart.go create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml create mode 100644 test-workflows/sample/loop-step.yaml create mode 100644 test-workflows/sample/with-threadshold.yaml diff --git a/cmd/cloud.go b/cmd/cloud.go index 955690b..ebd9ae1 100644 --- a/cmd/cloud.go +++ b/cmd/cloud.go @@ -62,7 +62,7 @@ func init() { } func runCloud(cmd *cobra.Command, _ []string) error { - utils.GoodF("Using the %v Engine %v by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR)) + utils.GoodF("Launching %v Engine %v developed by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR)) utils.InforF("Storing the log file to: %v", color.CyanString(options.LogFile)) // parse some arguments diff --git a/cmd/config.go b/cmd/config.go index 9e8b37d..fb141b8 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -30,6 +30,8 @@ func init() { configCmd.Flags().String("user", "", "Username") configCmd.Flags().String("pass", "", "Password") configCmd.Flags().StringP("workspace", "w", "", "Name of workspace") + configCmd.Flags().String("master-pass", "", "Set Master password for the API Authentication") + configCmd.SetHelpFunc(ConfigHelp) RootCmd.AddCommand(configCmd) } @@ -37,6 +39,7 @@ func init() { func runConfig(cmd *cobra.Command, args []string) error { sort.Strings(args) action, _ := cmd.Flags().GetString("action") + masterPass, _ := cmd.Flags().GetString("master-pass") workspace, _ := cmd.Flags().GetString("workspace") clientName, _ := cmd.Flags().GetString("client-name") @@ -98,7 +101,12 @@ func runConfig(cmd *cobra.Command, args []string) error { break } + if masterPass != "" { + core.SetMasterPassword(&options, masterPass) + break + } core.SetTactic(&options) + break case "update": core.Update(options) diff --git a/cmd/health.go b/cmd/health.go index 8a3a4d2..b4bd186 100644 --- a/cmd/health.go +++ b/cmd/health.go @@ -162,19 +162,15 @@ func generalCheck() error { if _, err = utils.RunCommandWithErr("timeout --help"); err != nil { errorBinary = append(errorBinary, "timeout") } - if _, err = utils.RunCommandWithErr("amass -h"); err != nil { - errorBinary = append(errorBinary, "amass") + if _, err = utils.RunCommandWithErr("subfinder -h"); err != nil { + errorBinary = append(errorBinary, "subfinder") } - if _, err = utils.RunCommandWithErr(fmt.Sprintf("%s -h", path.Join(options.Env.BinariesFolder, "httpx"))); err != nil { + if _, err = utils.RunCommandWithErr(("httpx -h")); err != nil { errorBinary = append(errorBinary, "httpx") } - // if _, err = utils.RunCommandWithErr(fmt.Sprintf("%s -h", path.Join(options.Env.BinariesFolder, "httprobe"))); err != nil { - // errorBinary = append(errorBinary, "httprobe") - // } - - if _, err = utils.RunCommandWithErr(fmt.Sprintf("%s -h", path.Join(options.Env.BinariesFolder, "nuclei"))); err != nil { + if _, err = utils.RunCommandWithErr("nuclei -h"); err != nil { errorBinary = append(errorBinary, "nuclei") } @@ -185,17 +181,18 @@ func generalCheck() error { fmt.Printf("[+] Health Check Core Programs: %s\n", color.GreenString("✔")) // Check core signatures - okVuln := false - if utils.DirLength("~/nuclei-templates") > 0 { - okVuln = true - } - if okVuln { - fmt.Printf("[+] Health Check Vulnerability scanning config: %s\n", color.GreenString("✔")) - } else { - color.Red("vulnerability scanning config setup incorrectly") - return fmt.Errorf("vulnerability scanning config setup incorrectly") - } + // okVuln := false + // if utils.DirLength("~/nuclei-templates") > 0 { + // okVuln = true + // } + + // if okVuln { + // fmt.Printf("[+] Health Check Vulnerability scanning config: %s\n", color.GreenString("✔")) + // } else { + // color.Red("vulnerability scanning config setup incorrectly") + // return fmt.Errorf("vulnerability scanning config setup incorrectly") + // } // check data folder if utils.FolderExists(options.Env.DataFolder) { diff --git a/cmd/root.go b/cmd/root.go index 296bef9..fb3b541 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -51,6 +51,7 @@ func init() { RootCmd.PersistentFlags().IntVarP(&options.Threads, "threads-hold", "B", 0, "Threads hold for each module (default: number of CPUs)") RootCmd.PersistentFlags().StringVar(&options.Tactics, "tactic", "default", "Choosing the tactic for running workflow from [default aggressive gently]") RootCmd.PersistentFlags().StringVar(&options.Scan.ParamsFile, "params-file", "", "Custom file params --params-file=params.yaml") + RootCmd.PersistentFlags().BoolVar(&options.Scan.DryRun, "dry-run", false, "Dry run mode to check the flow without executing anything") // cloud flags RootCmd.PersistentFlags().BoolVar(&options.Cloud.EnableChunk, "chunk", false, "Enable chunk mode") diff --git a/cmd/scan.go b/cmd/scan.go index 4892949..c9f3556 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -34,8 +34,7 @@ func init() { } func runScan(_ *cobra.Command, _ []string) error { - utils.GoodF("Using the %v Engine %v by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR)) - utils.InforF("Storing the log file to: %v", color.CyanString(options.LogFile)) + utils.GoodF("Launching %v Engine %v developed by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR)) var wg sync.WaitGroup p, _ := ants.NewPoolWithFunc(options.Concurrency, func(i interface{}) { diff --git a/cmd/server.go b/cmd/server.go index 5078255..8b81f10 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -28,6 +28,7 @@ func init() { serverCmd.Flags().BoolVar(&options.Server.DisableWorkspaceListing, "disable-listing", false, "Disable workspaces directtory listing") serverCmd.Flags().BoolVar(&options.Server.PreFork, "prefork", false, "Enable Prefork mode for the api server") serverCmd.Flags().BoolVarP(&options.Server.NoAuthen, "no-auth", "A", false, "Disable authentication for the api server") + serverCmd.Flags().BoolVar(&options.Server.BasicAuth, "basic-auth", false, "Turn on basic auth for the api server") serverCmd.SetHelpFunc(ServerHelp) RootCmd.AddCommand(serverCmd) @@ -43,7 +44,7 @@ func runServer(cmd *cobra.Command, _ []string) error { host, _ := cmd.Flags().GetString("host") port, _ := cmd.Flags().GetString("port") options.Server.Bind = fmt.Sprintf("%v:%v", host, port) - utils.GoodF("Using the %v Engine %v by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR)) + utils.GoodF("Launching %v Engine %v developed by %v", cases.Title(language.Und, cases.NoLower).String(libs.BINARY), color.HiCyanString(libs.VERSION), color.HiMagentaString(libs.AUTHOR)) server.StartServer(options) return nil } diff --git a/cmd/usage.go b/cmd/usage.go index 692bd1e..41b457e 100644 --- a/cmd/usage.go +++ b/cmd/usage.go @@ -162,7 +162,6 @@ func UtilsUsage() string { func ConfigUsage() string { h := color.HiCyanString("\nConfig Usage:\n") h += " osmedeus config [action] [OPTIONS] \n" - h += " osmedeus config init -p https://github.com/j3ssie/osmedeus-plugins\n" h += " osmedeus config --user newusser --pass newpassword\n" h += " osmedeus config clean \n" h += " osmedeus config delete -t woskapce \n" @@ -218,6 +217,7 @@ func ServerUsage() string { h += " osmedeus server --port 5000\n" h += " osmedeus server --disable-ssl\n" h += " osmedeus server -A --disable-ssl\n" + h += " osmedeus server --basic-auth --disable-ssl\n" return h } diff --git a/core/config.go b/core/config.go index 9f5ae1d..b0a6f30 100644 --- a/core/config.go +++ b/core/config.go @@ -62,6 +62,7 @@ func InitConfig(options *libs.Options) error { secret := utils.GenHash(utils.RandomString(8) + utils.GetTS())[:32] // only 32 char prefix := secret[len(secret)-20 : len(secret)-1] + master_password := utils.GenHash(utils.RandomString(20) + utils.GetTS())[:32] // only 32 char // set some default config if config file doesn't exist v.SetDefault("Server", map[string]string{ "bind": "0.0.0.0:8000", @@ -71,7 +72,7 @@ func InitConfig(options *libs.Options) error { "ui": path.Join(RootFolder, "server/ui"), "cert_file": path.Join(RootFolder, "server/ssl/cert.pem"), "key_file": path.Join(RootFolder, "server/ssl/key.pem"), - "master_pass": "", + "master_pass": master_password, }) v.SetDefault("Tactic", map[string]any{ @@ -379,3 +380,23 @@ func SetTactic(options *libs.Options) { v.WriteConfig() } + +func SetMasterPassword(options *libs.Options, masterPassword string) { + v = LoadConfig(options) + if err := v.ReadInConfig(); err != nil { + utils.ErrorF("Error reading config file, %s", err) + } + + if len(masterPassword) < 6 { + utils.ErrorF("Master password must be at least 6 characters") + os.Exit(-1) + } + + // baseThreads := options.Threads + redactedMasterPassword := masterPassword[:2] + strings.Repeat("*", len(masterPassword)-4) + masterPassword[len(masterPassword)-2:] + utils.InforF("Set server masterpassword to %v", color.HiCyanString("%v", redactedMasterPassword)) + + // set some default config if config file doesn't exist + v.Set("Server.master_pass", masterPassword) + v.WriteConfig() +} diff --git a/core/flowchart.go b/core/flowchart.go new file mode 100644 index 0000000..295114e --- /dev/null +++ b/core/flowchart.go @@ -0,0 +1,64 @@ +package core + +import ( + "fmt" + + "github.com/fatih/color" + + "github.com/j3ssie/osmedeus/utils" +) + +func (r *Runner) GenerateFlowChart() { + // spew.Dump(r.Routines) + + moduleGroups := make(map[string][]string) + for index, routine := range r.Routines { + moduleGroup := []string{} + for _, module := range routine.ParsedModules { + moduleGroup = append(moduleGroup, module.Name) + } + moduleGroups[fmt.Sprintf("%d", index)] = moduleGroup + } + + // Generate flowchart + flowchart := "flowchart LR\n" + for index, modules := range moduleGroups { + if len(modules) == 0 { + continue + } + + // Create nodes for each module in the group + for i, module := range modules { + currentNode := fmt.Sprintf("\t%s_%d[%s]", index, i, module) + if len(modules) > 1 { + currentNode = fmt.Sprintf("\t%s_%d(%s)", index, i, module) + } + flowchart += currentNode + "\n" + + // Connect to the next module in the same group + if i < len(modules)-1 { + flowchart += fmt.Sprintf("\t%s_%d --> %s_%d\n", index, i, index, i+1) + } + + // If this is the last module in the group, connect to the first module of the next group + if i == len(modules)-1 { + nextGroupIndex := fmt.Sprintf("%d", StringToInt(index)+1) + if nextModules, exists := moduleGroups[nextGroupIndex]; exists && len(nextModules) > 0 { + flowchart += fmt.Sprintf("\t%s_%d --> %s_0\n", index, i, nextGroupIndex) + } + } + } + } + + // fmt.Println(flowchart) + + flowChartFile := r.WorkspaceFolder + "/scan-flowchart.mermaid" + utils.InforF("Generate flowchart to: %v", color.HiCyanString("%v", flowChartFile)) + utils.WriteToFile(flowChartFile, flowchart) +} + +func StringToInt(s string) int { + val := 0 + fmt.Sscanf(s, "%d", &val) + return val +} diff --git a/core/module.go b/core/module.go index b678689..ca57512 100644 --- a/core/module.go +++ b/core/module.go @@ -206,7 +206,6 @@ func (r *Runner) RunStep(step libs.Step) (string, error) { if step.Source != "" { return r.RunStepWithSource(step) } - // if len(step.Commands) > 0 { r.RunCommands(step.Commands, step.Std) diff --git a/core/parse.go b/core/parse.go index fcab659..c247f2a 100644 --- a/core/parse.go +++ b/core/parse.go @@ -174,11 +174,12 @@ func ParseInput(raw string, options libs.Options) map[string]string { ROptions["Date"] = time.Now().Format("2006-01-02T15:04:05") ROptions["TimeStamp"] = utils.GetTS() ROptions["TS"] = time.Now().Format("2006-01-02") + "T" + utils.GetTS() + ROptions["Random"] = utils.GetRandString(8) /* --- start to load default Env --- */ // ~/osmedeus-base ROptions["BaseFolder"] = utils.NormalizePath(strings.TrimLeft(options.Env.BaseFolder, "/")) - ROptions["Plugins"] = options.Env.BinariesFolder + // ROptions["Plugins"] = options.Env.BinariesFolder ROptions["Binaries"] = options.Env.BinariesFolder ROptions["Backup"] = options.Env.BackupFolder diff --git a/core/reference.go b/core/reference.go index a61e729..1732533 100644 --- a/core/reference.go +++ b/core/reference.go @@ -102,7 +102,8 @@ const ( ) const ( - SetVar = "SetVar" - SetOSVar = "SetOSVar" - GetOSEnv = "GetOSEnv" + SetVar = "SetVar" + SetOSVar = "SetOSVar" + GetOSEnv = "GetOSEnv" + GetRandString = "GetRandString" ) diff --git a/core/runner.go b/core/runner.go index 6b10e5b..7d4272f 100644 --- a/core/runner.go +++ b/core/runner.go @@ -9,7 +9,6 @@ import ( "github.com/Shopify/yaml" "github.com/fatih/color" "github.com/j3ssie/osmedeus/database" - "github.com/j3ssie/osmedeus/execution" "github.com/j3ssie/osmedeus/libs" "github.com/j3ssie/osmedeus/utils" "github.com/panjf2000/ants" @@ -366,7 +365,6 @@ func (r *Runner) ResolveRoutine() { ThreadsFlags = append(ThreadsFlags, fmt.Sprintf("%v=%v", colorKey, value)) } } - } if len(toggleFlags) > 0 || len(skippingFlags) > 0 { @@ -393,11 +391,24 @@ func (r *Runner) Start() { r.DoneFile = r.Target["Output"] + "/done" r.RuntimeFile = r.Target["Output"] + "/runtime" r.WorkspaceFolder = r.Target["Output"] + + // update the log file + scanLogFile := r.WorkspaceFolder + "/execution.log" + utils.CopyFile(r.Opt.LogFile, scanLogFile) + r.Opt.LogFile = scanLogFile + utils.InitLog(&r.Opt) + utils.InforF("Storing the log file to: %v", color.CyanString(r.Opt.LogFile)) + + r.GenerateFlowChart() + if r.Opt.Scan.DryRun { + utils.InforF("Dry run mode enabled") + os.Exit(0) + } + os.Remove(r.DoneFile) utils.TSPrintF("Running the routine %v on %v", color.HiYellowString(r.RoutineName), color.CyanString(r.Input)) utils.InforF("Detailed runtime file can be found on %v", color.CyanString(r.RuntimeFile)) - execution.TeleSendMess(r.Opt, fmt.Sprintf("%s -- Start new scan: %s -- %s", r.Opt.Noti.ClientName, r.Opt.Scan.Flow, r.Target["Workspace"]), "#status", false) r.DBNewTarget() r.DBNewScan() diff --git a/core/runtime.go b/core/runtime.go index 58dbf68..da1f77b 100644 --- a/core/runtime.go +++ b/core/runtime.go @@ -250,6 +250,12 @@ func (r *Runner) LoadScripts() string { return returnValue }) + vm.Set(GetRandString, func(call otto.FunctionCall) otto.Value { + utils.InforF("%v", color.HiWhiteString(call.Argument(0).String())) + returnValue, _ := otto.ToValue(true) + return returnValue + }) + // Warnf simply print a string to console vm.Set(Warnf, func(call otto.FunctionCall) otto.Value { utils.InforF("%v", color.HiRedString(call.Argument(0).String())) diff --git a/core/update.go b/core/update.go index 8fb37f0..d9d7c84 100644 --- a/core/update.go +++ b/core/update.go @@ -299,7 +299,6 @@ func UpdateBase(opt libs.Options) { os.RemoveAll(goPath) utils.RunOSCommand(fmt.Sprintf("cp %s %s", newBin, goPath)) - // go path but in plugins folder goPath = path.Join(opt.Env.BinariesFolder, "go", libs.BINARY) os.RemoveAll(goPath) utils.RunOSCommand(fmt.Sprintf("cp %s %s", newBin, goPath)) diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..13977d2 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,537 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/osmp/delete/{wsname}": { + "delete": { + "description": "Delete a workspace and all its associated files", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Delete a workspace", + "parameters": [ + { + "type": "string", + "description": "Workspace name", + "name": "wsname", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Workspace successfully deleted", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + }, + "400": { + "description": "Workspace doesn't exist", + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + "/api/osmp/execute": { + "post": { + "description": "Execute a new scan with specified configuration", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "scans" + ], + "summary": "Start a new scan", + "parameters": [ + { + "description": "Scan configuration", + "name": "taskData", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/server.TaskData" + } + } + ], + "responses": { + "200": { + "description": "Scan started successfully", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "input": { + "type": "string" + } + } + } + } + } + ] + } + }, + "400": { + "description": "Invalid JSON payload", + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + "/api/osmp/flows": { + "get": { + "description": "Get all available workflow configurations and their modules", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "List available workflows", + "responses": { + "200": { + "description": "List of workflows with their details", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + }, + "400": { + "description": "Error when no workflow is found", + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + "/api/osmp/ps": { + "get": { + "description": "Get all currently running Osmedeus processes", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "processes" + ], + "summary": "List running processes", + "responses": { + "200": { + "description": "List of all running processes", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + } + } + } + }, + "/api/osmp/scans": { + "get": { + "description": "Get all running and completed scan processes", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "scans" + ], + "summary": "List all scan processes", + "responses": { + "200": { + "description": "List of all scan processes", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + } + } + } + }, + "/api/osmp/workspace/{wsname}": { + "get": { + "description": "Get detailed information about a specific workspace including reports", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Get workspace details", + "parameters": [ + { + "type": "string", + "description": "Workspace name", + "name": "wsname", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "workspace details and reports", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + } + } + } + ] + } + } + } + } + }, + "/login": { + "post": { + "description": "Authenticate user and return JWT token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "authentication" + ], + "summary": "User login", + "responses": { + "200": { + "description": "status=success, message=Successfully login, token=JWT_TOKEN", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "string" + } + } + } + } + }, + "/v1/health": { + "get": { + "description": "Get server health status and version information", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "health" + ], + "summary": "Check server health status", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + } + } + } + }, + "/v1/ping": { + "get": { + "description": "Simple ping endpoint to verify server is responding", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "Check server connectivity", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + } + } + } + }, + "/v1/workspaces": { + "get": { + "description": "Get all available workspaces", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Get all workspaces", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + } + } + } + } + }, + "definitions": { + "server.ResponseHTTP": { + "type": "object", + "properties": { + "data": {}, + "message": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "total": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "server.TaskData": { + "description": "Configuration for executing a new scan", + "type": "object", + "properties": { + "as_file": { + "type": "boolean", + "example": false + }, + "chunk": { + "type": "boolean", + "example": false + }, + "command": { + "type": "string" + }, + "concurrency": { + "type": "integer", + "example": 5 + }, + "debug": { + "type": "boolean", + "example": false + }, + "distributed": { + "type": "boolean", + "example": false + }, + "module": { + "type": "string", + "example": "subdomain" + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "[\"-deep\"", + " \"-aggressive\"]" + ] + }, + "password": { + "type": "string", + "example": "secret123" + }, + "target": { + "type": "string", + "example": "example.com" + }, + "targets": { + "type": "array", + "items": { + "type": "string" + } + }, + "targets_file": { + "type": "string", + "example": "/path/to/targets.txt" + }, + "test": { + "type": "boolean", + "example": false + }, + "threads": { + "type": "integer", + "example": 10 + }, + "timeout": { + "type": "string", + "example": "1h" + }, + "wildcard": { + "type": "boolean", + "example": false + }, + "workflow": { + "type": "string", + "example": "general" + }, + "workspace": { + "type": "string", + "example": "my-project" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..c70d7e1 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,508 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": { + "/api/osmp/delete/{wsname}": { + "delete": { + "description": "Delete a workspace and all its associated files", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Delete a workspace", + "parameters": [ + { + "type": "string", + "description": "Workspace name", + "name": "wsname", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Workspace successfully deleted", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + }, + "400": { + "description": "Workspace doesn't exist", + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + "/api/osmp/execute": { + "post": { + "description": "Execute a new scan with specified configuration", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "scans" + ], + "summary": "Start a new scan", + "parameters": [ + { + "description": "Scan configuration", + "name": "taskData", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/server.TaskData" + } + } + ], + "responses": { + "200": { + "description": "Scan started successfully", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "command": { + "type": "string" + }, + "input": { + "type": "string" + } + } + } + } + } + ] + } + }, + "400": { + "description": "Invalid JSON payload", + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + "/api/osmp/flows": { + "get": { + "description": "Get all available workflow configurations and their modules", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workflows" + ], + "summary": "List available workflows", + "responses": { + "200": { + "description": "List of workflows with their details", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + }, + "400": { + "description": "Error when no workflow is found", + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + } + } + } + } + }, + "/api/osmp/ps": { + "get": { + "description": "Get all currently running Osmedeus processes", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "processes" + ], + "summary": "List running processes", + "responses": { + "200": { + "description": "List of all running processes", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + } + } + } + }, + "/api/osmp/scans": { + "get": { + "description": "Get all running and completed scan processes", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "scans" + ], + "summary": "List all scan processes", + "responses": { + "200": { + "description": "List of all scan processes", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object" + } + } + } + } + ] + } + } + } + } + }, + "/api/osmp/workspace/{wsname}": { + "get": { + "description": "Get detailed information about a specific workspace including reports", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Get workspace details", + "parameters": [ + { + "type": "string", + "description": "Workspace name", + "name": "wsname", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "workspace details and reports", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/server.ResponseHTTP" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": true + } + } + } + ] + } + } + } + } + }, + "/login": { + "post": { + "description": "Authenticate user and return JWT token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "authentication" + ], + "summary": "User login", + "responses": { + "200": { + "description": "status=success, message=Successfully login, token=JWT_TOKEN", + "schema": { + "type": "object", + "additionalProperties": true + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "type": "string" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "string" + } + } + } + } + }, + "/v1/health": { + "get": { + "description": "Get server health status and version information", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "health" + ], + "summary": "Check server health status", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + } + } + } + }, + "/v1/ping": { + "get": { + "description": "Simple ping endpoint to verify server is responding", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "system" + ], + "summary": "Check server connectivity", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + }, + "503": { + "description": "Service Unavailable", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + } + } + } + }, + "/v1/workspaces": { + "get": { + "description": "Get all available workspaces", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "workspaces" + ], + "summary": "Get all workspaces", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/server.ResponseHTTP" + } + } + } + } + } + }, + "definitions": { + "server.ResponseHTTP": { + "type": "object", + "properties": { + "data": {}, + "message": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "total": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "server.TaskData": { + "description": "Configuration for executing a new scan", + "type": "object", + "properties": { + "as_file": { + "type": "boolean", + "example": false + }, + "chunk": { + "type": "boolean", + "example": false + }, + "command": { + "type": "string" + }, + "concurrency": { + "type": "integer", + "example": 5 + }, + "debug": { + "type": "boolean", + "example": false + }, + "distributed": { + "type": "boolean", + "example": false + }, + "module": { + "type": "string", + "example": "subdomain" + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "[\"-deep\"", + " \"-aggressive\"]" + ] + }, + "password": { + "type": "string", + "example": "secret123" + }, + "target": { + "type": "string", + "example": "example.com" + }, + "targets": { + "type": "array", + "items": { + "type": "string" + } + }, + "targets_file": { + "type": "string", + "example": "/path/to/targets.txt" + }, + "test": { + "type": "boolean", + "example": false + }, + "threads": { + "type": "integer", + "example": 10 + }, + "timeout": { + "type": "string", + "example": "1h" + }, + "wildcard": { + "type": "boolean", + "example": false + }, + "workflow": { + "type": "string", + "example": "general" + }, + "workspace": { + "type": "string", + "example": "my-project" + } + } + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..22a7122 --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,323 @@ +definitions: + server.ResponseHTTP: + properties: + data: {} + message: + type: string + status: + type: integer + total: + type: integer + type: + type: string + type: object + server.TaskData: + description: Configuration for executing a new scan + properties: + as_file: + example: false + type: boolean + chunk: + example: false + type: boolean + command: + type: string + concurrency: + example: 5 + type: integer + debug: + example: false + type: boolean + distributed: + example: false + type: boolean + module: + example: subdomain + type: string + params: + example: + - '["-deep"' + - ' "-aggressive"]' + items: + type: string + type: array + password: + example: secret123 + type: string + target: + example: example.com + type: string + targets: + items: + type: string + type: array + targets_file: + example: /path/to/targets.txt + type: string + test: + example: false + type: boolean + threads: + example: 10 + type: integer + timeout: + example: 1h + type: string + wildcard: + example: false + type: boolean + workflow: + example: general + type: string + workspace: + example: my-project + type: string + type: object +info: + contact: {} +paths: + /api/osmp/delete/{wsname}: + delete: + consumes: + - application/json + description: Delete a workspace and all its associated files + parameters: + - description: Workspace name + in: path + name: wsname + required: true + type: string + produces: + - application/json + responses: + "200": + description: Workspace successfully deleted + schema: + $ref: '#/definitions/server.ResponseHTTP' + "400": + description: Workspace doesn't exist + schema: + properties: + error: + type: string + type: object + summary: Delete a workspace + tags: + - workspaces + /api/osmp/execute: + post: + consumes: + - application/json + description: Execute a new scan with specified configuration + parameters: + - description: Scan configuration + in: body + name: taskData + required: true + schema: + $ref: '#/definitions/server.TaskData' + produces: + - application/json + responses: + "200": + description: Scan started successfully + schema: + allOf: + - $ref: '#/definitions/server.ResponseHTTP' + - properties: + data: + properties: + command: + type: string + input: + type: string + type: object + type: object + "400": + description: Invalid JSON payload + schema: + properties: + error: + type: string + type: object + summary: Start a new scan + tags: + - scans + /api/osmp/flows: + get: + consumes: + - application/json + description: Get all available workflow configurations and their modules + produces: + - application/json + responses: + "200": + description: List of workflows with their details + schema: + allOf: + - $ref: '#/definitions/server.ResponseHTTP' + - properties: + data: + items: + type: object + type: array + type: object + "400": + description: Error when no workflow is found + schema: + properties: + error: + type: string + type: object + summary: List available workflows + tags: + - workflows + /api/osmp/ps: + get: + consumes: + - application/json + description: Get all currently running Osmedeus processes + produces: + - application/json + responses: + "200": + description: List of all running processes + schema: + allOf: + - $ref: '#/definitions/server.ResponseHTTP' + - properties: + data: + items: + type: object + type: array + type: object + summary: List running processes + tags: + - processes + /api/osmp/scans: + get: + consumes: + - application/json + description: Get all running and completed scan processes + produces: + - application/json + responses: + "200": + description: List of all scan processes + schema: + allOf: + - $ref: '#/definitions/server.ResponseHTTP' + - properties: + data: + items: + type: object + type: array + type: object + summary: List all scan processes + tags: + - scans + /api/osmp/workspace/{wsname}: + get: + consumes: + - application/json + description: Get detailed information about a specific workspace including reports + parameters: + - description: Workspace name + in: path + name: wsname + required: true + type: string + produces: + - application/json + responses: + "200": + description: workspace details and reports + schema: + allOf: + - $ref: '#/definitions/server.ResponseHTTP' + - properties: + data: + additionalProperties: true + type: object + type: object + summary: Get workspace details + tags: + - workspaces + /login: + post: + consumes: + - application/json + description: Authenticate user and return JWT token + produces: + - application/json + responses: + "200": + description: status=success, message=Successfully login, token=JWT_TOKEN + schema: + additionalProperties: true + type: object + "401": + description: Unauthorized + schema: + type: string + "500": + description: Internal Server Error + schema: + type: string + summary: User login + tags: + - authentication + /v1/health: + get: + consumes: + - application/json + description: Get server health status and version information + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/server.ResponseHTTP' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/server.ResponseHTTP' + summary: Check server health status + tags: + - health + /v1/ping: + get: + consumes: + - application/json + description: Simple ping endpoint to verify server is responding + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/server.ResponseHTTP' + "503": + description: Service Unavailable + schema: + $ref: '#/definitions/server.ResponseHTTP' + summary: Check server connectivity + tags: + - system + /v1/workspaces: + get: + consumes: + - application/json + description: Get all available workspaces + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/server.ResponseHTTP' + summary: Get all workspaces + tags: + - workspaces +swagger: "2.0" diff --git a/execution/git.go b/execution/git.go index 620b248..003e719 100644 --- a/execution/git.go +++ b/execution/git.go @@ -96,7 +96,7 @@ func PushResult(storageFolder string, commitMess string, options libs.Options) { } } -// GitClone update latest UI and Plugins from default repo +// GitClone update latest UI and Base from default repo func GitClone(url string, dest string, forced bool, options libs.Options) { if options.NoGit || options.Storages["secret_key"] == "" { utils.WarnF("Storage Disable") diff --git a/execution/scripts.go b/execution/scripts.go index 9b8501c..d61f5f3 100644 --- a/execution/scripts.go +++ b/execution/scripts.go @@ -218,8 +218,6 @@ func ExtractTarGz(filename string) error { return err } - } - return nil } diff --git a/go.mod b/go.mod index 9584b1b..99c8ea6 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/j3ssie/osmedeus -go 1.21.6 +go 1.23.0 + +toolchain go1.23.6 require ( github.com/Jeffail/gabs/v2 v2.7.0 @@ -16,8 +18,9 @@ require ( github.com/go-playground/validator/v10 v10.19.0 github.com/go-resty/resty/v2 v2.12.0 github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 - github.com/gofiber/fiber/v2 v2.52.4 + github.com/gofiber/fiber/v2 v2.52.6 github.com/gofiber/jwt/v2 v2.2.7 + github.com/gofiber/swagger v1.1.1 github.com/gomarkdown/markdown v0.0.0-20240328165702-4d01890c35c0 github.com/hashicorp/go-version v1.6.0 github.com/jasonlvhit/gocron v0.0.1 @@ -37,39 +40,47 @@ require ( github.com/spf13/cast v1.6.0 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 + github.com/swaggo/swag v1.16.4 github.com/thoas/go-funk v0.9.3 github.com/x-cray/logrus-prefixed-formatter v0.5.2 github.com/xanzy/go-gitlab v0.101.0 - golang.org/x/crypto v0.21.0 - golang.org/x/net v0.23.0 + golang.org/x/crypto v0.37.0 + golang.org/x/net v0.39.0 golang.org/x/oauth2 v0.18.0 - golang.org/x/term v0.18.0 - golang.org/x/text v0.14.0 + golang.org/x/term v0.31.0 + golang.org/x/text v0.24.0 ) require ( - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/golang-jwt/jwt/v4 v4.0.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-querystring v1.1.0 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/klauspost/compress v1.17.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mailru/easyjson v0.9.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -77,7 +88,7 @@ require ( github.com/moul/http2curl v1.0.0 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.2.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/smartystreets/goconvey v1.8.1 // indirect @@ -85,17 +96,18 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/swaggo/files/v2 v2.0.2 // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect github.com/tklauser/numcpus v0.7.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.51.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect + github.com/valyala/fasthttp v1.60.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.32.0 // indirect golang.org/x/time v0.5.0 // indirect + golang.org/x/tools v0.32.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index ac2aae4..fb949c3 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,12 @@ github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg= github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Shopify/yaml v2.1.0+incompatible h1:Y7Wj6eQo5Byeaxb2M9FiPdKBQ3ooLsRIEmUZMMxCI8g= github.com/Shopify/yaml v2.1.0+incompatible/go.mod h1:Mrsv1G5Osez+VdHYcSI2zfaUzPu4lCdO9cW8R2lHPEc= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/aws/aws-sdk-go v1.51.14 h1:qedX6zZEO1a+5kra+D4ythOYR3TgaROC0hTPxhTFh8I= github.com/aws/aws-sdk-go v1.51.14/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -34,6 +36,14 @@ github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uq github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -50,10 +60,12 @@ github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1/go.mod h1:A2S0CWkNylc2 github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= -github.com/gofiber/fiber/v2 v2.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM= -github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI= +github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/gofiber/jwt/v2 v2.2.7 h1:MgXZV+ak+FiRVepD3btHBxWcyxlFzTDGXJv78dU1sIE= github.com/gofiber/jwt/v2 v2.2.7/go.mod h1:yaOHLccYXJidk1HX/EiIdIL+Z1xmY2wnIv6hgViw384= +github.com/gofiber/swagger v1.1.1 h1:FZVhVQQ9s1ZKLHL/O0loLh49bYB5l1HEAgxDlcTtkRA= +github.com/gofiber/swagger v1.1.1/go.mod h1:vtvY/sQAMc/lGTUCg0lqmBL7Ht9O7uzChpbvJeJQINw= github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -70,8 +82,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25dO0g= github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= @@ -101,13 +113,15 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= -github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -120,14 +134,15 @@ github.com/linode/linodego v1.31.0 h1:XY04rtgQfAzCWx3QUqIc9VVJ6usyLC5MoTEzrdAoIY github.com/linode/linodego v1.31.0/go.mod h1:y8GDP9uLVH4jTB9qyrgw79qfKdYJmNCGUOJmfuiOcmI= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -161,13 +176,14 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robertkrimen/otto v0.3.0 h1:5RI+8860NSxvXywDY9ddF5HcPw0puRsd8EgbXV0oqRE= github.com/robertkrimen/otto v0.3.0/go.mod h1:uW9yN1CYflmUQYvAMS0m+ZiNo3dMzRUDQJX0jWbzgxw= github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= @@ -205,10 +221,14 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files/v2 v2.0.2 h1:Bq4tgS/yxLB/3nwOMcul5oLEUKa877Ykgz3CJMVbQKU= +github.com/swaggo/files/v2 v2.0.2/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0= +github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= @@ -218,14 +238,15 @@ github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDgu github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= -github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= -github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/fasthttp v1.60.0 h1:kBRYS0lOhVJ6V+bYN8PqAHELKHtXqwq9zNMLKx1MBsw= +github.com/valyala/fasthttp v1.60.0/go.mod h1:iY4kDgV3Gc6EqhRZ8icqcmlG6bqhcDXfuHgTO4FXCvc= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xanzy/go-gitlab v0.101.0 h1:qRgvX8DNE19zRugB6rnnZMZ5ubhITSKPLNWEyc6UIPg= github.com/xanzy/go-gitlab v0.101.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= @@ -237,12 +258,15 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -254,8 +278,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -263,6 +287,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -274,20 +300,21 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -295,14 +322,17 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= @@ -322,8 +352,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/libs/options.go b/libs/options.go index d5c082a..fc044ee 100644 --- a/libs/options.go +++ b/libs/options.go @@ -86,6 +86,7 @@ type Scan struct { CustomWorkspace string SuffixName string Force bool + DryRun bool // this is true when calling from cloud scan RemoteCall bool } @@ -111,6 +112,7 @@ type Server struct { DisableSSL bool PreFork bool NoAuthen bool + BasicAuth bool PollingTime int Bind string diff --git a/libs/version.go b/libs/version.go index fb58272..57b02bb 100644 --- a/libs/version.go +++ b/libs/version.go @@ -4,7 +4,7 @@ import "fmt" const ( // VERSION of this project - VERSION = "v4.6.5" + VERSION = "v4.7.0" // DESC description of the tool DESC = "A Workflow Engine for Offensive Security" // BINARY name of osmedeus diff --git a/server/auth.go b/server/auth.go index 3f7a11f..0ba73af 100644 --- a/server/auth.go +++ b/server/auth.go @@ -9,8 +9,15 @@ import ( "github.com/gofiber/fiber/v2" ) -// authen stuff - +// @Summary User login +// @Description Authenticate user and return JWT token +// @Tags authentication +// @Accept json +// @Produce json +// @Success 200 {object} map[string]interface{} "status=success, message=Successfully login, token=JWT_TOKEN" +// @Failure 401 {string} string "Unauthorized" +// @Failure 500 {string} string "Internal Server Error" +// @Router /login [post] func Login(c *fiber.Ctx) error { type LoginInput struct { Username string `json:"username"` diff --git a/server/builder.go b/server/builder.go index eee0a13..9c1e0b8 100644 --- a/server/builder.go +++ b/server/builder.go @@ -2,12 +2,13 @@ package server import ( "fmt" - "github.com/gofiber/fiber/v2" - "github.com/j3ssie/osmedeus/libs" - "github.com/j3ssie/osmedeus/utils" "os" "path" "strings" + + "github.com/gofiber/fiber/v2" + "github.com/j3ssie/osmedeus/libs" + "github.com/j3ssie/osmedeus/utils" ) // UploadData data required in json form @@ -78,15 +79,12 @@ func CommandBuilder(taskData *TaskData) string { } } - if taskData.ScanID != "" { - binary += fmt.Sprintf(" --sid %v ", taskData.ScanID) - } - var command string var workspace, concurrency, timeout, params, workflow, plugin, scanID string if len(taskData.TargetsList) > 0 { taskData.TargetsFile = SaveTargets(taskData.TargetsList) + taskData.Target = taskData.TargetsFile utils.DebugF("Save targets list to: %v", taskData.TargetsFile) } @@ -96,18 +94,6 @@ func CommandBuilder(taskData *TaskData) string { workspace = fmt.Sprintf(" -w '%v'", taskData.Workspace) } - if taskData.Binary != "" { - binary = taskData.Binary - } - - //if taskData.RawName { - // binary = binary + " --rt " - //} - - if taskData.ViewOnly { - binary = binary + " --view-only " - } - // default workflow is general if taskData.WorkFlow != "" { workflow = fmt.Sprintf(" -f '%v'", taskData.WorkFlow) @@ -135,8 +121,8 @@ func CommandBuilder(taskData *TaskData) string { } } - if taskData.PluginName != "" { - plugin = fmt.Sprintf(" -m '%v'", taskData.PluginName) + if taskData.ModuleName != "" { + plugin = fmt.Sprintf(" -m '%v'", taskData.ModuleName) } // override everything @@ -145,7 +131,7 @@ func CommandBuilder(taskData *TaskData) string { } // mean general scan - if taskData.PluginName == "" { + if taskData.ModuleName == "" { command = fmt.Sprintf("%v %v -t %v %v%v%v%v", binary, workflow, taskData.Target, concurrency, timeout, workspace, params) if taskData.TargetsFile != "" { command = fmt.Sprintf("%v %v -T %v %v%v%v%v", binary, workflow, taskData.TargetsFile, concurrency, timeout, workspace, params) diff --git a/server/mics.go b/server/mics.go index ba035e4..ca6e99f 100644 --- a/server/mics.go +++ b/server/mics.go @@ -12,6 +12,13 @@ import ( "github.com/j3ssie/osmedeus/libs" ) +// @Summary List running processes +// @Description Get all currently running Osmedeus processes +// @Tags processes +// @Accept json +// @Produce json +// @Success 200 {object} ResponseHTTP{data=[]object} "List of all running processes" +// @Router /api/osmp/ps [get] func Process(c *fiber.Ctx) error { processes := execution.GetOsmProcess("") return c.JSON(ResponseHTTP{ @@ -36,6 +43,14 @@ func RawWorkspace(c *fiber.Ctx) error { }) } +// @Summary List available workflows +// @Description Get all available workflow configurations and their modules +// @Tags workflows +// @Accept json +// @Produce json +// @Success 200 {object} ResponseHTTP{data=[]object} "List of workflows with their details" +// @Failure 400 {object} object{error=string} "Error when no workflow is found" +// @Router /api/osmp/flows [get] func ListFlows(c *fiber.Ctx) error { flows := core.ListFlow(Opt) if len(flows) == 0 { diff --git a/server/ping.go b/server/ping.go index 9852e82..904e578 100644 --- a/server/ping.go +++ b/server/ping.go @@ -5,15 +5,15 @@ import ( "github.com/j3ssie/osmedeus/libs" ) -// Ping is a function to get all books data from database -// @Summary Get all books -// @Description Get all books -// @Tags books +// Ping is a function to check server connectivity +// @Summary Check server connectivity +// @Description Simple ping endpoint to verify server is responding +// @Tags system // @Accept json // @Produce json // @Success 200 {object} ResponseHTTP{} // @Failure 503 {object} ResponseHTTP{} -// @Router /v1/books [get] +// @Router /v1/ping [get] func Ping(c *fiber.Ctx) error { return c.JSON(ResponseHTTP{ Status: 200, @@ -21,15 +21,15 @@ func Ping(c *fiber.Ctx) error { }) } -// Health is a function to get all books data from database -// @Summary Get all books -// @Description Get all books -// @Tags books +// Health is a function to check server health status +// @Summary Check server health status +// @Description Get server health status and version information +// @Tags health // @Accept json // @Produce json // @Success 200 {object} ResponseHTTP{} // @Failure 503 {object} ResponseHTTP{} -// @Router /v1/books [get] +// @Router /v1/health [get] func Health(c *fiber.Ctx) error { return c.JSON(ResponseHTTP{ Status: 200, diff --git a/server/router.go b/server/router.go index 442aeb1..9e361f7 100644 --- a/server/router.go +++ b/server/router.go @@ -11,13 +11,15 @@ import ( "github.com/fatih/color" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/basicauth" "github.com/gofiber/fiber/v2/middleware/cors" - jwtware "github.com/gofiber/jwt/v2" - "github.com/j3ssie/osmedeus/libs" - "github.com/j3ssie/osmedeus/utils" - "github.com/gofiber/fiber/v2/middleware/filesystem" "github.com/gofiber/fiber/v2/middleware/logger" + jwtware "github.com/gofiber/jwt/v2" + "github.com/gofiber/swagger" + _ "github.com/j3ssie/osmedeus/docs" + "github.com/j3ssie/osmedeus/libs" + "github.com/j3ssie/osmedeus/utils" ) // var DB *gorm.DB @@ -73,6 +75,8 @@ func StartServer(options libs.Options) { // SetupRoutes setup router api func SetupRoutes(app *fiber.App) { // for UI + // Swagger UI endpoint + app.Get(fmt.Sprintf("%s/swagger/*", Opt.Server.StaticPrefix), swagger.HandlerDefault) app.Static("/ui", Opt.Server.UIPath) app.Get("/ui/*", func(ctx *fiber.Ctx) error { return ctx.SendFile(path.Join(Opt.Server.UIPath, "index.html")) @@ -98,18 +102,29 @@ func SetupRoutes(app *fiber.App) { // disable JWT Middleware when -A is set if !Opt.Server.NoAuthen { - app.Use(jwtware.New(jwtware.Config{ - SigningKey: []byte(Opt.Server.JWTSecret), - Filter: nil, - SuccessHandler: nil, - ErrorHandler: jwtError, - SigningKeys: nil, - SigningMethod: "", - ContextKey: "", - Claims: nil, - TokenLookup: "", - AuthScheme: "Osmedeus", - })) + if Opt.Server.BasicAuth { + utils.InforF("Master Password is enabled") + // Provide a minimal config + basicAuth := basicauth.New(basicauth.Config{ + Users: map[string]string{ + "osmedeus": Opt.Server.MasterPassword, + }, + }) + app.Use(basicAuth) + } else { + app.Use(jwtware.New(jwtware.Config{ + SigningKey: []byte(Opt.Server.JWTSecret), + Filter: nil, + SuccessHandler: nil, + ErrorHandler: jwtError, + SigningKeys: nil, + SigningMethod: "", + ContextKey: "", + Claims: nil, + TokenLookup: "", + AuthScheme: "Osmedeus", + })) + } } // Middleware @@ -127,18 +142,6 @@ func SetupRoutes(app *fiber.App) { osmp.Get("/raw", RawWorkspace) osmp.Get("/flows", ListFlows) osmp.Get("/help", HelperMessage) - - //api.Use(basicauth.New(basicauth.Config{ - // Users: map[string]string{ - // Opt.Client.Username: Opt.Client.Password, - // }, - // Realm: "Forbidden", - // Unauthorized: func(c *fiber.Ctx) error { - // return c.SendString("404 not found") - // }, - //})) - // - // execute endpoints osmp.Post("/execute", NewScan) osmp.Post("/upload", Upload) diff --git a/server/scan.go b/server/scan.go index 42ec9d6..3263dc0 100644 --- a/server/scan.go +++ b/server/scan.go @@ -6,48 +6,55 @@ import ( ) // TaskData data required in json form +// TaskData represents the scan configuration and parameters +// @Description Configuration for executing a new scan type TaskData struct { - MasterPassword string `json:"password"` - Binary string `json:"binary"` - // override everything below - Command string `json:"command"` + MasterPassword string `json:"password" example:"secret123" description:"Master password for authentication"` + Command string `json:"command" description:"Override command to execute (optional)"` - // these two not be blank when run with plugins - WorkFlow string `json:"workflow"` - PluginName string `json:"plugin"` - ScanID string `json:"scan_id"` + Target string `json:"target" example:"example.com" description:"Target to scan"` + TargetsList []string `json:"targets" description:"List of targets to scan (optional)"` + WorkFlow string `json:"workflow" example:"general" description:"Workflow name to execute"` - // for select scan + task - Workspace string `json:"workspace"` - Target string `json:"target"` - TargetsList []string `json:"targets"` - TargetsFile string `json:"targets_file"` - - AliveAssets bool `json:"alive_assets"` // skip targets part and select the assets from DB - AllAssets bool `json:"all_assets"` // skip targets part and select the assets from DB - - // just more mics info for custom command later - Params []string `json:"params"` - Timeout string `json:"timeout"` - Concurrency int `json:"concurrency"` - - // enable distributed scan - Distributed bool `json:"distributed"` - - // for chunk mode only - Threads int `json:"threads"` - Chunk bool `json:"chunk"` - TargetAsFile bool `json:"as_file"` - - // only select record not run the command - RawName bool `json:"RawName"` - WildCard bool `json:"wildcard"` - ViewOnly bool `json:"view_only"` - Debug bool `json:"debug"` - Test bool `json:"test"` + ModuleName string `json:"module" example:"subdomain" description:"Plugin name to run (optional)"` + Workspace string `json:"workspace" example:"my-project" description:"Workspace name (optional)"` + TargetsFile string `json:"targets_file" example:"/path/to/targets.txt" description:"File containing targets (optional)"` + Threads int `json:"threads" example:"10" description:"Number of concurrent threads (optional)"` + Chunk bool `json:"chunk" example:"false" description:"Enable chunk mode (optional)"` + TargetAsFile bool `json:"as_file" example:"false" description:"Treat target as file (optional)"` + Params []string `json:"params" example:"[\"-deep\", \"-aggressive\"]" description:"Additional parameters (optional)"` + Timeout string `json:"timeout" example:"1h" description:"Scan timeout (optional)"` + Concurrency int `json:"concurrency" example:"5" description:"Concurrency level (optional)"` + Distributed bool `json:"distributed" example:"false" description:"Enable distributed scanning (optional)"` + WildCard bool `json:"wildcard" example:"false" description:"Enable wildcard mode (optional)"` + Debug bool `json:"debug" example:"false" description:"Enable debug mode (optional)"` + Test bool `json:"test" example:"false" description:"Test mode without actual execution (optional)"` } -// NewScan new scan +// @Summary Start a new scan +// @Description Execute a new scan with specified configuration +// @Tags scans +// @Accept json +// @Produce json +// @Param taskData body TaskData true "Scan configuration" +// @Success 200 {object} ResponseHTTP{data=object{command=string,input=string}} "Scan started successfully" +// @Failure 400 {object} object{error=string} "Invalid JSON payload" +// @Example Request-SingleTarget +// +// { +// "target": "example.com", +// "workflow": "general" +// } +// +// @Example Request-MultipleTargets +// +// { +// "targets": ["1.2.3.4/24", "5.6.7.8/24"], +// "as_file": true, +// "workflow": "cidr" +// } +// +// @Router /api/osmp/execute [post] func NewScan(c *fiber.Ctx) error { var taskData TaskData var invalid bool @@ -81,6 +88,7 @@ func NewScan(c *fiber.Ctx) error { Status: 200, Data: fiber.Map{ "command": taskData.Command, + "input": taskData.Target, }, Type: "new-scan", Message: "New Scan Imported", @@ -121,7 +129,6 @@ func NewScanCloud(c *fiber.Ctx) error { Status: 200, Data: fiber.Map{ "input": taskData.Target, - "scan_id": taskData.ScanID, "workflow": taskData.WorkFlow, }, Type: "new-scan", diff --git a/server/workspace.go b/server/workspace.go index 3a1746e..501da5e 100644 --- a/server/workspace.go +++ b/server/workspace.go @@ -21,10 +21,10 @@ type ResponseHTTP struct { Message string `json:"message"` } -// Workspace is a function to get all books data from database -// @Summary Get all books -// @Description Get all books -// @Tags books +// ListWorkspaces is a function to get all workspaces from database +// @Summary Get all workspaces +// @Description Get all available workspaces +// @Tags workspaces // @Accept json // @Produce json // @Success 200 {object} ResponseHTTP{} @@ -40,6 +40,14 @@ func ListWorkspaces(c *fiber.Ctx) error { }) } +// @Summary Get workspace details +// @Description Get detailed information about a specific workspace including reports +// @Tags workspaces +// @Accept json +// @Produce json +// @Param wsname path string true "Workspace name" +// @Success 200 {object} ResponseHTTP{data=map[string]interface{}} "workspace details and reports" +// @Router /api/osmp/workspace/{wsname} [get] func WorkspaceDetail(c *fiber.Ctx) error { wsname := c.Params("wsname") workspace := database.GetSingleScan(wsname, Opt) @@ -86,6 +94,13 @@ func WorkspaceDetail(c *fiber.Ctx) error { }) } +// @Summary List all scan processes +// @Description Get all running and completed scan processes +// @Tags scans +// @Accept json +// @Produce json +// @Success 200 {object} ResponseHTTP{data=[]object} "List of all scan processes" +// @Router /api/osmp/scans [get] func ListAllScan(c *fiber.Ctx) error { scan := database.GetScanProgress(Opt) return c.JSON(ResponseHTTP{ @@ -97,6 +112,15 @@ func ListAllScan(c *fiber.Ctx) error { }) } +// @Summary Delete a workspace +// @Description Delete a workspace and all its associated files +// @Tags workspaces +// @Accept json +// @Produce json +// @Param wsname path string true "Workspace name" +// @Success 200 {object} ResponseHTTP "Workspace successfully deleted" +// @Failure 400 {object} object{error=string} "Workspace doesn't exist" +// @Router /api/osmp/delete/{wsname} [delete] func DeleteWorkspace(c *fiber.Ctx) error { wsname := c.Params("wsname") wsDir := path.Join(Opt.Env.WorkspacesFolder, utils.NormalizePath(wsname)) diff --git a/test-workflows/flow-with-params.yaml b/test-workflows/flow-with-params.yaml index 0a7fb01..41e5d3b 100644 --- a/test-workflows/flow-with-params.yaml +++ b/test-workflows/flow-with-params.yaml @@ -8,4 +8,8 @@ params: routines: - modules: - timeout-module + - with-threadshold + - modules: + - loop-step + # - parallel diff --git a/test-workflows/sample/loop-step.yaml b/test-workflows/sample/loop-step.yaml new file mode 100644 index 0000000..94d6f3d --- /dev/null +++ b/test-workflows/sample/loop-step.yaml @@ -0,0 +1,20 @@ +name: loop-step + +report: + final: + - "/tmp/ott/source.txt" + +steps: + - scripts: + - "ExecCmd('mkdir -p /tmp/ott/')" + - "ExecCmd('seq 4 > /tmp/ott/source.txt')" + + - source: '/tmp/ott/source.txt' + threads: '{{ 9 / 2 }}' + commands: + - "echo '---> {{line}} '" + - "sleep 2 && echo '---> done {{line}}'" + + - scripts: + - "ExecCmd('sleep 3')" + - "ExecCmd('echo \\'<======\\' ')" diff --git a/test-workflows/sample/with-threadshold.yaml b/test-workflows/sample/with-threadshold.yaml new file mode 100644 index 0000000..b44fb9a --- /dev/null +++ b/test-workflows/sample/with-threadshold.yaml @@ -0,0 +1,14 @@ +name: with-threads-hold + +steps: + - commands: + - "echo 'calc ---> {{ 5555 * threads}} '" + scripts: + - "ExecCmd('mkdir -p /tmp/ott/')" + - "ExecCmd('seq 10 > /tmp/ott/source.txt')" + + - source: '/tmp/ott/source.txt' + threads: '2' + commands: + - "echo '---> {{ 2 * threads}} '" + # - "sleep 1 && echo '---> done [[.line]]'" diff --git a/test-workflows/test-module/new-params.yaml b/test-workflows/test-module/new-params.yaml index acee8f9..72d190b 100644 --- a/test-workflows/test-module/new-params.yaml +++ b/test-workflows/test-module/new-params.yaml @@ -1,14 +1,16 @@ name: new-params -desc: new-params +desc: new-params desc params: - NewParams: "{{Company}}" - WS: "{{Workspace}}" steps: - - required: - - "{{testFile}}" - commands: + - commands: + - "echo '/tmp/' > /tmp/sammm" + + - commands: - "echo 'Company --> {{Company}}'" - "echo 'NewParams --> {{NewParams}}'" - - "echo 'WS --> {{WS}}'" \ No newline at end of file + - "echo 'WS --> {{WS}}'" + - 'ls -la $(cat /tmp/sammm)' diff --git a/utils/helper.go b/utils/helper.go index c1f34c2..b443db3 100644 --- a/utils/helper.go +++ b/utils/helper.go @@ -957,3 +957,40 @@ func RenderText(format string, data map[string]string) string { } return buf.String() } + +// CopyFile attempts to copy a file from src to dst, first trying a hard link then falling back to a regular copy +func CopyFile(src, dst string) error { + // Normalize paths + src = NormalizePath(src) + dst = NormalizePath(dst) + + // First try creating a hard link + if err := os.Link(src, dst); err == nil { + return nil + } + + // If hard link fails, do a regular file copy + input, err := os.ReadFile(src) + if err != nil { + return fmt.Errorf("failed to read source file: %v", err) + } + + if err := os.WriteFile(dst, input, 0644); err != nil { + return fmt.Errorf("failed to write destination file: %v", err) + } + + return nil +} + +func GetRandString(length int) string { + const charset = "abcdefghijklmnopqrstuvwxyz0123456789" + // Create a new random source seeded with current timestamp + source := rand.NewSource(time.Now().UnixNano()) + seededRand := rand.New(source) + + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + return string(b) +}