// Transform a mig-console style search query into a set of parameters to send to the API // // This function is similar to the function in mig-console, however we do not include // parameters that are not relevant to agents. func parseSearchQuery(querystring string) (p migdbsearch.Parameters, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("parseSearchQuery() -> %v", e) } }() p = migdbsearch.NewParameters() p.Type = "agent" orders := strings.Split(querystring, " ") if len(orders) == 0 { panic("no criteria specified") } for _, order := range orders { if order == "and" { continue } params := strings.Split(order, "=") if len(params) != 2 { panic(fmt.Sprintf("Invalid `key=value` in search parameter '%s'", order)) } key := params[0] value := params[1] // if the string contains % characters, used in postgres's pattern matching, // escape them properly switch key { case "after": p.After, err = time.Parse(time.RFC3339, value) if err != nil { panic("after date not in RFC3339 format, ex: 2015-09-23T14:14:16Z") } case "agentid": p.AgentID = value case "agentname": p.AgentName = value case "agentversion": p.AgentVersion = value case "before": p.Before, err = time.Parse(time.RFC3339, value) if err != nil { panic("before date not in RFC3339 format, ex: 2015-09-23T14:14:16Z") } case "limit": p.Limit, err = strconv.ParseFloat(value, 64) if err != nil { panic("invalid limit parameter") } case "status": p.Status = value case "name": p.AgentName = value default: panic(fmt.Sprintf("Unknown search key '%s'", key)) } } return }
// parseSearchQuery transforms a search string into an API query func parseSearchQuery(orders []string) (p migdbsearch.Parameters, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("parseSearchQuery() -> %v", e) } }() p = migdbsearch.NewParameters() p.Type = orders[1] if len(orders) < 4 { panic("Invalid search syntax. try `search help`.") } if orders[2] != "where" { panic(fmt.Sprintf("Expected keyword 'where' after search type. Got '%s'", orders[2])) } for _, order := range orders[3:len(orders)] { if order == "and" { continue } params := strings.Split(order, "=") if len(params) != 2 { panic(fmt.Sprintf("Invalid `key=value` in search parameter '%s'", order)) } key := params[0] value := params[1] // if the string contains % characters, used in postgres's pattern matching, // escape them properly switch key { case "actionname": p.ActionName = value case "actionid": p.ActionID = value case "after": p.After, err = time.Parse(time.RFC3339, value) if err != nil { panic("after date not in RFC3339 format, ex: 2015-09-23T14:14:16Z") } case "agentid": p.AgentID = value case "agentname": p.AgentName = value case "agentversion": p.AgentVersion = value case "before": p.Before, err = time.Parse(time.RFC3339, value) if err != nil { panic("before date not in RFC3339 format, ex: 2015-09-23T14:14:16Z") } case "commandid": p.CommandID = value case "investigatorid": p.InvestigatorID = value case "investigatorname": p.InvestigatorName = value case "limit": p.Limit, err = strconv.ParseFloat(value, 64) if err != nil { panic("invalid limit parameter") } case "status": p.Status = value case "name": switch p.Type { case "action", "command": p.ActionName = value case "agent": p.AgentName = value case "investigator": p.InvestigatorName = value } default: panic(fmt.Sprintf("Unknown search key '%s'", key)) } } return }
// parseSearchParameters transforms a query string into search parameters in the migdb format func parseSearchParameters(qp url.Values) (p migdbsearch.Parameters, filterFound bool, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("parseSearchParameters()-> %v", e) } }() p = migdbsearch.NewParameters() for queryParams, _ := range qp { switch queryParams { case "actionname": p.ActionName = qp["actionname"][0] case "actionid": p.ActionID = qp["actionid"][0] case "after": p.After, err = time.Parse(time.RFC3339, qp["after"][0]) if err != nil { panic("after date not in RFC3339 format") } case "agentid": p.AgentID = qp["agentid"][0] case "agentname": p.AgentName = qp["agentname"][0] case "agentversion": p.AgentVersion = qp["agentversion"][0] case "before": p.Before, err = time.Parse(time.RFC3339, qp["before"][0]) if err != nil { panic("before date not in RFC3339 format") } case "commandid": p.CommandID = qp["commandid"][0] case "foundanything": if truere.MatchString(qp["foundanything"][0]) { p.FoundAnything = true } else if falsere.MatchString(qp["foundanything"][0]) { p.FoundAnything = false } else { panic("foundanything parameter must be true or false") } filterFound = true case "investigatorid": p.InvestigatorID = qp["investigatorid"][0] case "investigatorname": p.InvestigatorName = qp["investigatorname"][0] case "limit": p.Limit, err = strconv.ParseFloat(qp["limit"][0], 64) if err != nil { panic("invalid limit parameter") } case "loadername": p.LoaderName = qp["loadername"][0] case "loaderid": p.LoaderID = qp["loaderid"][0] case "manifestname": p.ManifestName = qp["manifestname"][0] case "manifestid": p.ManifestID = qp["manifestid"][0] case "offset": p.Offset, err = strconv.ParseFloat(qp["offset"][0], 64) if err != nil { panic("invalid offset parameter") } case "report": switch qp["report"][0] { case "complianceitems": p.Report = qp["report"][0] case "geolocations": p.Report = qp["report"][0] default: panic("report not implemented") } case "status": p.Status = qp["status"][0] case "target": p.Target = qp["target"][0] case "threatfamily": p.ThreatFamily = qp["threatfamily"][0] case "type": p.Type = qp["type"][0] } } return }