// investigatorReader retrieves an agent from the api // and enters prompt mode to analyze it func investigatorReader(input string, cli client.Client) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("investigatorReader() -> %v", e) } }() inputArr := strings.Split(input, " ") if len(inputArr) < 2 { panic("wrong order format. must be 'investigator <investigatorid>'") } iid, err := strconv.ParseFloat(inputArr[1], 64) if err != nil { panic(err) } inv, err := cli.GetInvestigator(iid) if err != nil { panic(err) } fmt.Println("Entering investigator mode. Type \x1b[32;1mexit\x1b[0m or press \x1b[32;1mctrl+d\x1b[0m to leave. \x1b[32;1mhelp\x1b[0m may help.") fmt.Printf("Investigator %.0f named '%s'\n", inv.ID, inv.Name) prompt := fmt.Sprintf("\x1b[35;1minv %.0f>\x1b[0m ", iid) for { // completion var symbols = []string{"details", "exit", "help", "pubkey", "r", "lastactions"} 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(prompt) if err == io.EOF { break } if err != nil { fmt.Println("error: ", err) break } orders := strings.Split(strings.TrimSpace(input), " ") switch orders[0] { case "details": fmt.Printf("Investigator ID %.0f\nname %s\nstatus %s\nadmin %v\nkey id %s\ncreated %s\nmodified %s\n", inv.ID, inv.Name, inv.Status, inv.IsAdmin, inv.PGPFingerprint, inv.CreatedAt, inv.LastModified) case "exit": fmt.Printf("exit\n") goto exit case "help": fmt.Printf(`The following orders are available: details print the details of the investigator exit exit this mode help show this help lastactions <limit> print the last actions ran by the investigator. limit=10 by default. pubkey show the armored public key of the investigator r refresh the investigator (get latest version from upstream) setadmin <true|false> enable or disable admin flag for investigator setstatus <status> changes the status of the investigator to <status> (can be 'active' or 'disabled') `) case "lastactions": limit := 10 if len(orders) > 1 { limit, err = strconv.Atoi(orders[1]) if err != nil { panic(err) } } err = printInvestigatorLastActions(iid, limit, cli) if err != nil { panic(err) } case "pubkey": armoredPubKey, err := pgp.ArmorPubKey(inv.PublicKey) if err != nil { panic(err) } fmt.Printf("%s\n", armoredPubKey) case "r": inv, err = cli.GetInvestigator(iid) if err != nil { panic(err) } fmt.Println("Reload succeeded") case "setstatus": if len(orders) != 2 { fmt.Println("error: must be 'setstatus <status>'. try 'help'") break } newstatus := orders[1] err = cli.PostInvestigatorStatus(iid, newstatus) if err != nil { panic(err) } else { fmt.Println("Investigator status set to", newstatus) } inv, err = cli.GetInvestigator(iid) if err != nil { panic(err) } case "setadmin": if len(orders) != 2 { fmt.Println("error: must be 'setadmin <true|false>'. try 'help'") break } var flag bool valid := true switch strings.ToLower(orders[1]) { case "true": flag = true case "false": flag = false default: fmt.Println("error: must specify true or false") valid = false } if !valid { break } err = cli.PostInvestigatorAdminFlag(iid, flag) if err != nil { panic(err) } else { fmt.Println("Investigator admin flag set to", flag) } inv, err = cli.GetInvestigator(iid) if err != nil { panic(err) } case "": break default: fmt.Printf("Unknown order '%s'. You are in investigator mode. Try `help`.\n", orders[0]) } readline.AddHistory(input) } exit: fmt.Printf("\n") return }