Fix some bugs and refactor the API server

This commit is contained in:
j3ssie
2025-04-21 21:12:47 +08:00
parent a30570cc6c
commit ee467daff7
36 changed files with 1828 additions and 190 deletions
+1 -1
View File
@@ -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
+8
View File
@@ -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)
+15 -18
View File
@@ -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) {
+1
View File
@@ -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")
+1 -2
View File
@@ -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{}) {
+2 -1
View File
@@ -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
}
+1 -1
View File
@@ -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
}
+22 -1
View File
@@ -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()
}
+64
View File
@@ -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
}
-1
View File
@@ -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)
+2 -1
View File
@@ -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
+4 -3
View File
@@ -102,7 +102,8 @@ const (
)
const (
SetVar = "SetVar"
SetOSVar = "SetOSVar"
GetOSEnv = "GetOSEnv"
SetVar = "SetVar"
SetOSVar = "SetOSVar"
GetOSEnv = "GetOSEnv"
GetRandString = "GetRandString"
)
+14 -3
View File
@@ -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()
+6
View File
@@ -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()))
-1
View File
@@ -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))
+537
View File
@@ -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)
}
+508
View File
@@ -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"
}
}
}
}
}
+323
View File
@@ -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"
+1 -1
View File
@@ -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")
-2
View File
@@ -218,8 +218,6 @@ func ExtractTarGz(filename string) error {
return err
}
}
return nil
}
+27 -15
View File
@@ -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
+60 -29
View File
@@ -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=
+2
View File
@@ -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
+1 -1
View File
@@ -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
+9 -2
View File
@@ -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"`
+8 -22
View File
@@ -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)
+15
View File
@@ -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 {
+10 -10
View File
@@ -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,
+31 -28
View File
@@ -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)
+45 -38
View File
@@ -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",
+28 -4
View File
@@ -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))
+4
View File
@@ -8,4 +8,8 @@ params:
routines:
- modules:
- timeout-module
- with-threadshold
- modules:
- loop-step
# - parallel
+20
View File
@@ -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 \\'<======\\' ')"
@@ -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]]'"
+7 -5
View File
@@ -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}}'"
- "echo 'WS --> {{WS}}'"
- 'ls -la $(cat /tmp/sammm)'
+37
View File
@@ -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)
}