func main() { var cconf client.Configuration if len(os.Args) != 2 { fmt.Printf("usage: %v [- | indicator_post_url]\n", os.Args[0]) os.Exit(1) } postOut = os.Args[1] dbg := os.Getenv("DEBUG") if dbg != "" { noVerify = true } confpath := path.Join(client.FindHomedir(), ".migrc") cconf, err := client.ReadConfiguration(confpath) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } cconf, err = client.ReadEnvConfiguration(cconf) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } cli, err := client.NewClient(cconf, "migindicators") if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } agents, err := cli.EvaluateAgentTarget(agentTarget) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } var indparam slib.IndicatorParams for _, agt := range agents { ind, err := agentToIndicator(agt) if err != nil { fmt.Fprintf(os.Stderr, "error converting agent to indicator: %v", err) continue } indparam.Indicators = append(indparam.Indicators, ind) } err = sendIndicators(indparam) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s - Search for MIG Agents\n"+ "Usage: %s name='some.agent.example.net' OR name='some.other.agent.example.com'\n", os.Args[0], os.Args[0]) flag.PrintDefaults() } var err error homedir := client.FindHomedir() var config = flag.String("c", homedir+"/.migrc", "Load configuration from file") var showversion = flag.Bool("V", false, "Show build version and exit") flag.Parse() if *showversion { fmt.Println(mig.Version) os.Exit(0) } // instanciate an API client conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } cli, err := client.NewClient(conf, "agent-search-"+mig.Version) if err != nil { panic(err) } agents, err := cli.EvaluateAgentTarget(strings.Join(flag.Args(), " ")) if err != nil { panic(err) } fmt.Println("name; id; status; version; mode; os; arch; pid; starttime; heartbeattime; operator; ident; publicip; addresses") for _, agt := range agents { operator := "unknown" if _, ok := agt.Tags.(map[string]interface{})["operator"]; ok { operator = agt.Tags.(map[string]interface{})["operator"].(string) } fmt.Printf("\"%s\"; \"%.0f\"; \"%s\"; \"%s\"; \"%s\"; \"%s\"; \"%s\"; \"%d\"; \"%s\"; \"%s\"; \"%s\"; \"%s\"; \"%s\"; \"%s\"\n", agt.Name, agt.ID, agt.Status, agt.Version, agt.Mode, agt.Env.OS, agt.Env.Arch, agt.PID, agt.StartTime.Format(time.RFC3339), agt.HeartBeatTS.Format(time.RFC3339), operator, agt.Env.Ident, agt.Env.PublicIP, agt.Env.Addresses) } }
func initContext(config string) (ctx Context, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("initContext() -> %v", e) } }() ctx = Context{} ctx.Channels.Log = make(chan mig.Log, 37) ctx.Channels.Results = make(chan mig.RunnerResult, 64) ctx.Channels.ExitNotify = make(chan bool, 64) ctx.Entities = make(map[string]*entity) err = gcfg.ReadFileInto(&ctx, config) if err != nil { panic(err) } ctx.Runner.RunDirectory = path.Join(ctx.Runner.Directory, "runners") ctx.Runner.PluginDirectory = path.Join(ctx.Runner.Directory, "plugins") if ctx.Client.ClientConfPath == "default" { hdir := client.FindHomedir() ctx.Client.ClientConfPath = path.Join(hdir, ".migrc") } ctx.ClientConf, err = client.ReadConfiguration(ctx.Client.ClientConfPath) if err != nil { panic(err) } if ctx.Client.Passphrase != "" { client.ClientPassphrase(ctx.Client.Passphrase) } ctx.Logging, err = mig.InitLogger(ctx.Logging, "mig-runner") if err != nil { panic(err) } return ctx, nil }
func main() { var ( conf client.Configuration cli client.Client err error op mig.Operation a mig.Action migrc, show, render, target, expiration, afile string verbose bool modargs []string run interface{} ) defer func() { if e := recover(); e != nil { fmt.Fprintf(os.Stderr, "%v\n", e) } }() homedir := client.FindHomedir() fs := flag.NewFlagSet("mig flag", flag.ContinueOnError) fs.Usage = continueOnFlagError fs.StringVar(&migrc, "c", homedir+"/.migrc", "alternative configuration file") fs.StringVar(&show, "show", "found", "type of results to show") fs.StringVar(&render, "render", "text", "results rendering mode") fs.StringVar(&target, "t", fmt.Sprintf("status='%s' AND mode='daemon'", mig.AgtStatusOnline), "action target") fs.StringVar(&expiration, "e", "300s", "expiration") fs.StringVar(&afile, "i", "/path/to/file", "Load action from file") fs.BoolVar(&verbose, "v", false, "Enable verbose output") // if first argument is missing, or is help, print help // otherwise, pass the remainder of the arguments to the module for parsing // this client is agnostic to module parameters if len(os.Args) < 2 || os.Args[1] == "help" || os.Args[1] == "-h" || os.Args[1] == "--help" { usage() } if len(os.Args) < 2 || os.Args[1] == "-V" { fmt.Println(version) os.Exit(0) } // when reading the action from a file, go directly to launch if os.Args[1] == "-i" { err = fs.Parse(os.Args[1:]) if err != nil { panic(err) } if afile == "/path/to/file" { panic("-i flag must take an action file path as argument") } a, err = mig.ActionFromFile(afile) if err != nil { panic(err) } fmt.Fprintf(os.Stderr, "[info] launching action from file, all flags are ignored\n") goto readytolaunch } // arguments parsing works as follow: // * os.Args[1] must contain the name of the module to launch. we first verify // that a module exist for this name and then continue parsing // * os.Args[2:] contains both global options and module parameters. We parse the // whole []string to extract global options, and module parameters will be left // unparsed in fs.Args() // * fs.Args() with the module parameters is passed as a string to the module parser // which will return a module operation to store in the action op.Module = os.Args[1] if _, ok := modules.Available[op.Module]; !ok { panic("Unknown module " + op.Module) } // -- Ugly hack Warning -- // Parse() will fail on the first flag that is not defined, but in our case module flags // are defined in the module packages and not in this program. Therefore, the flag parse error // is expected. Unfortunately, Parse() writes directly to stderr and displays the error to // the user, which confuses them. The right fix would be to prevent Parse() from writing to // stderr, since that's really the job of the calling program, but in the meantime we work around // it by redirecting stderr to null before calling Parse(), and put it back to normal afterward. // for ref, issue is at https://github.com/golang/go/blob/master/src/flag/flag.go#L793 fs.SetOutput(os.NewFile(uintptr(87592), os.DevNull)) err = fs.Parse(os.Args[2:]) fs.SetOutput(nil) if err != nil { // ignore the flag not defined error, which is expected because // module parameters are defined in modules and not in main if len(err.Error()) > 30 && err.Error()[0:29] == "flag provided but not defined" { // requeue the parameter that failed modargs = append(modargs, err.Error()[31:]) } else { // if it's another error, panic panic(err) } } for _, arg := range fs.Args() { modargs = append(modargs, arg) } run = modules.Available[op.Module].NewRun() if _, ok := run.(modules.HasParamsParser); !ok { fmt.Fprintf(os.Stderr, "[error] module '%s' does not support command line invocation\n", op.Module) os.Exit(2) } op.Parameters, err = run.(modules.HasParamsParser).ParamsParser(modargs) if err != nil || op.Parameters == nil { panic(err) } // If running against the local target, don't post the action to the MIG API // but run it locally instead. if target == "local" { msg, err := modules.MakeMessage(modules.MsgClassParameters, op.Parameters) if err != nil { panic(err) } out := run.(modules.Runner).Run(bytes.NewBuffer(msg)) if len(out) == 0 { panic("got empty results, run failed") } if _, ok := run.(modules.HasResultsPrinter); ok { var modres modules.Result err := json.Unmarshal([]byte(out), &modres) if err != nil { panic(err) } outRes, err := run.(modules.HasResultsPrinter).PrintResults(modres, true) if err != nil { panic(err) } for _, resLine := range outRes { fmt.Println(resLine) } } else { out = fmt.Sprintf("%s\n", out) } os.Exit(0) } a.Operations = append(a.Operations, op) for _, arg := range os.Args[1:] { a.Name += arg + " " } a.Target = target readytolaunch: // instanciate an API client conf, err = client.ReadConfiguration(migrc) if err != nil { panic(err) } cli, err = client.NewClient(conf, "cmd-"+version) if err != nil { panic(err) } if verbose { cli.EnableDebug() } // set the validity 60 second in the past to deal with clock skew a.ValidFrom = time.Now().Add(-60 * time.Second).UTC() period, err := time.ParseDuration(expiration) if err != nil { panic(err) } a.ExpireAfter = a.ValidFrom.Add(period) // add extra 60 seconds taken for clock skew a.ExpireAfter = a.ExpireAfter.Add(60 * time.Second).UTC() asig, err := cli.SignAction(a) if err != nil { panic(err) } a = asig // evaluate target before launch, give a change to cancel before going out to agents agents, err := cli.EvaluateAgentTarget(a.Target) if err != nil { panic(err) } fmt.Fprintf(os.Stderr, "\x1b[33m%d agents will be targeted. ctrl+c to cancel. launching in \x1b[0m", len(agents)) for i := 5; i > 0; i-- { time.Sleep(1 * time.Second) fmt.Fprintf(os.Stderr, "\x1b[33m%d\x1b[0m ", i) } fmt.Fprintf(os.Stderr, "\x1b[33mGO\n\x1b[0m") // launch and follow a, err = cli.PostAction(a) if err != nil { panic(err) } c := make(chan os.Signal, 1) done := make(chan bool, 1) signal.Notify(c, os.Interrupt) go func() { err = cli.FollowAction(a) if err != nil { panic(err) } done <- true }() select { case <-c: fmt.Fprintf(os.Stderr, "stop following action. agents may still be running. printing available results:\n") goto printresults case <-done: goto printresults } printresults: err = cli.PrintActionResults(a, show, render) if err != nil { panic(err) } }
func main() { var err error defer func() { if e := recover(); e != nil { fmt.Printf("FATAL: %v\n", e) } }() homedir := client.FindHomedir() var Usage = func() { fmt.Fprintf(os.Stderr, "Mozilla InvestiGator Action Generator\n"+ "usage: %s -i <input file>\n\n"+ "Command line to generate and sign MIG Actions.\n"+ "Configuration is read from ~/.migrc by default.\n\n"+ "Options:\n", os.Args[0]) flag.PrintDefaults() } // command line options var config = flag.String("c", homedir+"/.migrc", "Load configuration from file") var pretty = flag.Bool("p", false, "Print signed action in pretty JSON format") var urlencode = flag.Bool("urlencode", false, "URL Encode marshalled JSON before printing it (implies '-p')") var file = flag.String("i", "/path/to/file", "Load action from file") var target = flag.String("t", "some.target.example.net", "Set the target of the action") var validfrom = flag.String("validfrom", "now", "(optional) set an ISO8601 date the action will be valid from. If unset, use 'now'.") var expireafter = flag.String("expireafter", "30m", "(optional) set a validity duration for the action. If unset, use '30m'.") var nolaunch = flag.Bool("nolaunch", false, "Don't launch the action. Print it and exit. (implies '-p')") var showversion = flag.Bool("V", false, "Show build version and exit") flag.Parse() if *showversion { fmt.Println(version) os.Exit(0) } if *nolaunch { *pretty = true } // instanciate an API client conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } cli, err := client.NewClient(conf, "generator-"+version) if err != nil { panic(err) } // We need a file to load the action from if *file == "/path/to/file" { fmt.Println("ERROR: Missing action file") Usage() os.Exit(1) } a, err := mig.ActionFromFile(*file) if err != nil { panic(err) } // set the dates if *validfrom == "now" { // for immediate execution, set validity one minute in the past a.ValidFrom = time.Now().Add(-60 * time.Second).UTC() } else { a.ValidFrom, err = time.Parse(time.RFC3339, *validfrom) if err != nil { panic(err) } } period, err := time.ParseDuration(*expireafter) if err != nil { log.Fatal(err) } a.ExpireAfter = a.ValidFrom.Add(period) if *target != "some.target.example.net" { a.Target = *target } asig, err := cli.SignAction(a) if err != nil { panic(err) } a = asig // if asked, pretty print the action var jsonAction []byte if *pretty { jsonAction, err = json.MarshalIndent(a, "", "\t") fmt.Printf("%s\n", jsonAction) } else { jsonAction, err = json.Marshal(a) } if err != nil { panic(err) } // if asked, url encode the action before marshaling it actionstr := string(jsonAction) if *urlencode { strJsonAction := string(jsonAction) actionstr = url.QueryEscape(strJsonAction) if *pretty { fmt.Println(actionstr) } } if !*nolaunch { a2, err := cli.PostAction(a) if err != nil { panic(err) } fmt.Printf("Successfully launched action %.0f\n", a2.ID) } }
func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, `%s <query> - Search for MIG Agents Usage: %s "name='some.agent.example.net' OR name='some.other.agent.example.com'" A search query is a SQL WHERE condition. It can filter on any field present in the MIG Agents table. Column | Type -----------------+------------------------- id | numeric name | character varying(2048) queueloc | character varying(2048) mode | character varying(2048) version | character varying(2048) pid | integer starttime | timestamp with time zone destructiontime | timestamp with time zone heartbeattime | timestamp with time zone status | character varying(255) environment | json tags | json The "environment" and "tags" fields are free JSON fields and can be queried using Postgresql's JSON querying syntax. Below is an example of environment document: { "addresses": [ "172.21.0.3/20", "fe80::3602:86ff:fe2b:6fdd/64" ], "arch": "amd64", "ident": "Debian testing-updates sid", "init": "upstart", "isproxied": false, "os": "linux", "publicip": "172.21.0.3" } Below is an example of tags document: {"operator":"linuxwall"} EXAMPLE QUERIES --------------- Agent name "myserver.example.net" $ mig-agent-search "name='myserver.example.net'" All Linux agents: $ mig-agent-search "environment->>'os'='linux'" Ubuntu agents running 32 bits $ mig-agent-search "environment->>'ident' LIKE 'Ubuntu%%' AND environment->>'arch'='386' MacOS agents in datacenter SCL3 $ mig-agent-search "environment->>'os'='darwin' AND name LIKE '%%\.scl3\.%%' Agents with uptime greater than 30 days $ mig-agent-search "starttime < NOW() - INTERVAL '30 days'" Linux agents in checkin mode that are currently idle but woke up in the last hour $ mig-agent-search "mode='checkin' AND environment->>'os'='linux' AND status='idle' AND starttime > NOW() - INTERVAL '1 hour'" Agents operated by team "opsec" $ mig-agent-search "tags->>'operator'='opsec'" Command line flags: `, os.Args[0], os.Args[0]) flag.PrintDefaults() } var err error homedir := client.FindHomedir() var config = flag.String("c", homedir+"/.migrc", "Load configuration from file") var showversion = flag.Bool("V", false, "Show build version and exit") flag.Parse() if *showversion { fmt.Println(mig.Version) os.Exit(0) } // instanciate an API client conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } cli, err := client.NewClient(conf, "agent-search-"+mig.Version) if err != nil { panic(err) } agents, err := cli.EvaluateAgentTarget(strings.Join(flag.Args(), " ")) if err != nil { panic(err) } fmt.Println("name; id; status; version; mode; os; arch; pid; starttime; heartbeattime; tags; environment") for _, agt := range agents { tags, err := json.Marshal(agt.Tags) if err != nil { panic(err) } env, err := json.Marshal(agt.Env) if err != nil { panic(err) } fmt.Printf("%s; %.0f; %s; %s; %s; %s; %s; %d; %s; %s; %s; %s\n", agt.Name, agt.ID, agt.Status, agt.Version, agt.Mode, agt.Env.OS, agt.Env.Arch, agt.PID, agt.StartTime.Format(time.RFC3339), agt.HeartBeatTS.Format(time.RFC3339), tags, env) } }
func main() { defer func() { if e := recover(); e != nil { fmt.Fprintf(os.Stderr, "error: %v\n", e) os.Exit(1) } }() flag.Usage = func() { fmt.Fprintf(os.Stderr, `%s <query> - Search for MIG Agents Usage: %s -p "console style query" | -t "target style query" The -p or -t flag must be specified. CONSOLE MODE QUERY ------------------ The console mode query allows specific of a query string as would be passed in mig-console using "search agent". It returns all matching agents. EXAMPLE CONSOLE MODE QUERIES ---------------------------- All online agents: $ mig-agent-search -p "status=online" All agents regardless of status: $ mig-agent-search -p "status=%%" See the output of "search help" in mig-console for additional information on how to format these queries. TARGET MODE QUERY ----------------- The target mode query allows specification of an agent targeting string as would be passed to the -t flag using MIG command line. This evaluates agents using the targeting string as the command line would, returning matching agents. A search query is a SQL WHERE condition. It can filter on any field present in the MIG Agents table. Column | Type -----------------+------------------------- id | numeric name | character varying(2048) queueloc | character varying(2048) mode | character varying(2048) version | character varying(2048) pid | integer starttime | timestamp with time zone destructiontime | timestamp with time zone heartbeattime | timestamp with time zone status | character varying(255) environment | json tags | json The "environment" and "tags" fields are free JSON fields and can be queried using Postgresql's JSON querying syntax. Below is an example of environment document: { "addresses": [ "172.21.0.3/20", "fe80::3602:86ff:fe2b:6fdd/64" ], "arch": "amd64", "ident": "Debian testing-updates sid", "init": "upstart", "isproxied": false, "os": "linux", "publicip": "172.21.0.3" } Below is an example of tags document: {"operator":"linuxwall"} EXAMPLE TARGET MODE QUERIES --------------------------- Agent name "myserver.example.net" $ mig-agent-search -t "name='myserver.example.net'" All Linux agents: $ mig-agent-search -t "environment->>'os'='linux'" Ubuntu agents running 32 bits $ mig-agent-search -t "environment->>'ident' LIKE 'Ubuntu%%' AND environment->>'arch'='386'" MacOS agents in datacenter SCL3 $ mig-agent-search -t "environment->>'os'='darwin' AND name LIKE '%%\.scl3\.%%'" Agents with uptime greater than 30 days $ mig-agent-search -t "starttime < NOW() - INTERVAL '30 days'" Linux agents in checkin mode that are currently idle but woke up in the last hour $ mig-agent-search -t "mode='checkin' AND environment->>'os'='linux' AND status='idle' AND starttime > NOW() - INTERVAL '1 hour'" Agents operated by team "opsec" $ mig-agent-search -t "tags->>'operator'='opsec'" Command line flags: `, os.Args[0], os.Args[0]) flag.PrintDefaults() } var err error homedir := client.FindHomedir() var config = flag.String("c", homedir+"/.migrc", "Load configuration from file") var showversion = flag.Bool("V", false, "Show build version and exit") var paramSearch = flag.String("p", "", "Search using mig-console search style query") var targetSearch = flag.String("t", "", "Search using agent targeting string") flag.Parse() if *showversion { fmt.Println(mig.Version) os.Exit(0) } // Instantiate an API client conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } cli, err := client.NewClient(conf, "agent-search-"+mig.Version) if err != nil { panic(err) } if *paramSearch != "" { // Search using mig-console style keywords p, err := parseSearchQuery(*paramSearch) if err != nil { panic(err) } resources, err := cli.GetAPIResource("search?" + p.String()) if err != nil { panic(err) } fmt.Println("name; id; status; version; mode; os; arch; pid; starttime; heartbeattime; tags; environment") for _, item := range resources.Collection.Items { for _, data := range item.Data { if data.Name != "agent" { continue } agt, err := client.ValueToAgent(data.Value) if err != nil { panic(err) } err = printAgent(agt) if err != nil { panic(err) } } } } else if *targetSearch != "" { // Search using an agent targeting string agents, err := cli.EvaluateAgentTarget(*targetSearch) if err != nil { panic(err) } fmt.Println("name; id; status; version; mode; os; arch; pid; starttime; heartbeattime; tags; environment") for _, agt := range agents { err = printAgent(agt) if err != nil { panic(err) } } } else { panic("must specify -p or -t, see help") } os.Exit(0) }
func main() { var err error var Usage = func() { fmt.Fprintf(os.Stderr, "Mozilla InvestiGator Action Verifier\n"+ "usage: %s <-a action file> <-c command file>\n\n"+ "Command line to verify an action *or* command.\n"+ "Options:\n", os.Args[0]) flag.PrintDefaults() } hasaction := false hascommand := false homedir := client.FindHomedir() // command line options var actionfile = flag.String("a", "/path/to/action", "Load action from file") var commandfile = flag.String("c", "/path/to/command", "Load command from file") var config = flag.String("conf", homedir+"/.migrc", "Load configuration from file") var showversion = flag.Bool("V", false, "Show build version and exit") flag.Parse() if *showversion { fmt.Println(mig.Version) os.Exit(0) } conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } // if a file is defined, load action from that if *actionfile != "/path/to/action" { hasaction = true } if *commandfile != "/path/to/command" { hascommand = true } if (hasaction && hascommand) || (!hasaction && !hascommand) { fmt.Println("[error] either an action file or a command file must be provided") Usage() os.Exit(1) } var a mig.Action if hasaction { a, err = mig.ActionFromFile(*actionfile) if err != nil { panic(err) } } else { c, err := mig.CmdFromFile(*commandfile) if err != nil { panic(err) } a = c.Action } err = a.Validate() if err != nil { fmt.Println(err) } pubringFile, err := os.Open(conf.GPG.Home + "/pubring.gpg") if err != nil { panic(err) } defer pubringFile.Close() // syntax checking err = a.VerifySignatures(pubringFile) if err != nil { fmt.Println("[error]", err) } else { fmt.Println("Valid signature") } }
func main() { var err error defer func() { if e := recover(); e != nil { fmt.Fprintf(os.Stderr, "FATAL: %v\n", e) } }() homedir := client.FindHomedir() // command line options var config = flag.String("c", homedir+"/.migrc", "Load configuration from file") var quiet = flag.Bool("q", false, "don't display banners and prompts") var showversion = flag.Bool("V", false, "show build version and exit") var verbose = flag.Bool("v", false, "verbose output, includes debug information and raw queries") flag.Parse() if *showversion { fmt.Println(mig.Version) os.Exit(0) } // silence extra output out := os.Stdout if *quiet { out.Close() out, err = os.Open(os.DevNull) if err != nil { panic(err) } } defer out.Close() fmt.Fprintf(out, "\x1b[32;1m"+banner+"\x1b[0m") // append a space after completion readline.CompletionAppendChar = 0x20 // load history historyfile := homedir + "/.mig_history" fi, err := os.Stat(historyfile) if err == nil && fi.Size() > 0 { err = readline.LoadHistory(historyfile) if err != nil { fmt.Fprintf(os.Stderr, "failed to load history from %s\n", historyfile) } } // instanciate an API client conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } cli, err := client.NewClient(conf, "console-"+mig.Version) if err != nil { panic(err) } if *verbose { cli.EnableDebug() } // print platform status err = printStatus(cli) if err != nil { log.Fatal(err) } fmt.Fprintf(out, "\nConnected to %s. Exit with \x1b[32;1mctrl+d\x1b[0m. Type \x1b[32;1mhelp\x1b[0m for help.\n", cli.Conf.API.URL) for { // completion var symbols = []string{"action", "agent", "create", "command", "help", "history", "exit", "manifest", "showcfg", "status", "investigator", "search", "query", "where", "and", "loader"} readline.Completer = func(query, ctx string) []string { var res []string for _, sym := range symbols { if strings.HasPrefix(sym, query) { res = append(res, sym) } } return res } input, err := readline.String("\x1b[32;1mmig>\x1b[0m ") if err == io.EOF { break } if err != nil { fmt.Println("error: ", err) break } orders := strings.Split(strings.TrimSpace(input), " ") switch orders[0] { case "action": if len(orders) == 2 { err = actionReader(input, cli) if err != nil { log.Println(err) } } else { fmt.Println("error: missing action id in 'action <id>'") } case "agent": err = agentReader(input, cli) if err != nil { log.Println(err) } case "create": if len(orders) == 2 { switch orders[1] { case "action": var a mig.Action err = actionLauncher(a, cli) case "investigator": err = investigatorCreator(cli) case "loader": err = loaderCreator(cli) case "manifest": err = manifestCreator(cli) default: fmt.Printf("unknown order 'create %s'\n", orders[1]) } if err != nil { log.Println(err) } } else { fmt.Println("error: missing order, must be 'create <action|investigator>'") } case "command": err = commandReader(input, cli) if err != nil { log.Println(err) } case "exit": fmt.Printf("exit\n") goto exit case "help": fmt.Printf(`The following orders are available: action <id> enter interactive action reader mode for action <id> agent <id> enter interactive agent reader mode for agent <id> create action create a new action create investigator create a new investigator, will prompt for name and public key create loader create a new loader entry create manifest create a new manifest command <id> enter command reader mode for command <id> exit leave help show this help history <count> print last <count> entries in history. count=10 by default. investigator <id> enter interactive investigator management mode for investigator <id> manifest <id> enter manifest management mode for manifest <id> query <uri> send a raw query string, without the base url, to the api search <search> perform a search. see "search help" for more information. showcfg display running configuration status display platform status: connected agents, latest actions, ... `) case "history": var count int64 = 10 if len(orders) > 1 { count, err = strconv.ParseInt(orders[1], 10, 64) if err != nil { log.Println(err) break } } for i := readline.HistorySize(); i > 0 && count > 0; i, count = i-1, count-1 { fmt.Println(readline.GetHistory(i - 1)) } case "investigator": err = investigatorReader(input, cli) if err != nil { log.Println(err) } case "loader": err = loaderReader(input, cli) if err != nil { log.Println(err) } case "manifest": err = manifestReader(input, cli) if err != nil { log.Println(err) } case "query": fmt.Println("querying", orders[1]) r, err := http.NewRequest("GET", orders[1], nil) if err != nil { panic(err) } resp, err := cli.Do(r) if err != nil { panic(err) } if err != nil || resp.Body == nil { log.Println("query failed") } else { body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Printf("%s\n", body) } case "search": err = search(input, cli) if err != nil { log.Println(err) } case "showcfg": fmt.Printf("homedir = %s\n[api]\n url = %s\n[gpg]\n home = %s\n keyid = %s\n", cli.Conf.API.URL, cli.Conf.Homedir, cli.Conf.GPG.Home, cli.Conf.GPG.KeyID) case "status": err = printStatus(cli) if err != nil { log.Println(err) } case "": break default: fmt.Printf("Unknown order '%s'\n", orders[0]) } readline.AddHistory(input) } exit: fmt.Fprintf(out, footer) err = readline.SaveHistory(historyfile) if err != nil { fmt.Fprintf(os.Stderr, "failed to save history to %s\n", historyfile) } }