зеркало из https://github.com/mozilla/mig.git
[minor] add loader search to console
This commit is contained in:
Родитель
81fa03c320
Коммит
da8bbb2ee5
|
@ -407,12 +407,18 @@ func (cli Client) GetManifestLoaders(mid float64) (ldrs []mig.LoaderEntry, err e
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if resource.Collection.Items[0].Data[0].Name != "loaders" {
|
||||
panic("API returned something that is not a loader list... something's wrong.")
|
||||
}
|
||||
ldrs, err = ValueToLoaderEntries(resource.Collection.Items[0].Data[0].Value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
for _, item := range resource.Collection.Items {
|
||||
for _, data := range item.Data {
|
||||
if data.Name != "loader" {
|
||||
continue
|
||||
}
|
||||
ldr, err := ValueToLoaderEntry(data.Value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ldrs = append(ldrs, ldr)
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -600,7 +606,7 @@ func ValueToAction(v interface{}) (a mig.Action, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func ValueToLoaderEntries(v interface{}) (l []mig.LoaderEntry, err error) {
|
||||
func ValueToLoaderEntry(v interface{}) (l mig.LoaderEntry, err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("ValueToLoaderEntries() -> %v", e)
|
||||
|
|
|
@ -88,7 +88,7 @@ func main() {
|
|||
// completion
|
||||
var symbols = []string{"action", "agent", "create", "command", "help", "history",
|
||||
"exit", "manifest", "showcfg", "status", "investigator", "search", "query",
|
||||
"where", "and"}
|
||||
"where", "and", "loader"}
|
||||
readline.Completer = func(query, ctx string) []string {
|
||||
var res []string
|
||||
for _, sym := range symbols {
|
||||
|
|
|
@ -29,10 +29,10 @@ func search(input string, cli client.Client) (err error) {
|
|||
}
|
||||
sType := ""
|
||||
switch orders[1] {
|
||||
case "action", "agent", "command", "investigator", "manifest":
|
||||
case "action", "agent", "command", "investigator", "manifest", "loader":
|
||||
sType = orders[1]
|
||||
case "", "help":
|
||||
fmt.Printf(`usage: search <action|agent|command|investigator|manifest> where <key>=<value> [and <key>=<value>...]
|
||||
fmt.Printf(`usage: search <action|agent|command|investigator|loader|manifest> where <key>=<value> [and <key>=<value>...]
|
||||
|
||||
Example:
|
||||
mig> search command where agentname=%%khazad%% and investigatorname=%%vehent%% and actionname=%%memory%% and after=2015-09-09T17:00:00Z
|
||||
|
@ -91,6 +91,11 @@ The following search parameters are available, per search type:
|
|||
- manifestname=<str> search manifests by name
|
||||
- status=<str> search manifests by status amongst: active, staged, disabled
|
||||
|
||||
* loader:
|
||||
- loaderid=<id> search loaders by id
|
||||
- loadername=<str> search loaders by loader name
|
||||
- agentname=<str> search loaders for associated agent names
|
||||
|
||||
All searches accept the 'limit=<num>' parameter to limits the number of results returned by a search, defaults to 100
|
||||
Parameters that accept a <str> can use wildcards * and % (ex: name=jul%veh% ).
|
||||
No spaces are permitted within parameters. Spaces are used to separate search parameters.
|
||||
|
@ -123,6 +128,8 @@ No spaces are permitted within parameters. Spaces are used to separate search pa
|
|||
fmt.Println("- ID - + ---- Name ---- + --- Status ---")
|
||||
case "manifest":
|
||||
fmt.Println("- ID - + ---- Name ---- + -- Status -- + -------------- Target -------- + ---- Timestamp ---")
|
||||
case "loader":
|
||||
fmt.Println("- ID - + ---- Name ---- + ---- Agent Name ---- + -- Last Used ---")
|
||||
}
|
||||
for _, item := range resources.Collection.Items {
|
||||
for _, data := range item.Data {
|
||||
|
@ -228,6 +235,32 @@ No spaces are permitted within parameters. Spaces are used to separate search pa
|
|||
}
|
||||
fmt.Printf("%6.0f %s %s %s %s\n", mr.ID, name,
|
||||
status, target, mr.Timestamp)
|
||||
case "loader":
|
||||
le, err := client.ValueToLoaderEntry(data.Value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
loadername := le.Name
|
||||
if len(loadername) < 24 {
|
||||
for i := len(loadername); i < 24; i++ {
|
||||
loadername += " "
|
||||
}
|
||||
}
|
||||
if len(loadername) > 24 {
|
||||
loadername = loadername[0:21] + "..."
|
||||
}
|
||||
agtname := le.AgentName
|
||||
if len(agtname) < 24 {
|
||||
for i := len(agtname); i < 24; i++ {
|
||||
agtname += " "
|
||||
}
|
||||
}
|
||||
if len(agtname) > 24 {
|
||||
agtname = agtname[0:21] + "..."
|
||||
}
|
||||
fmt.Printf("%6.0f %s %s %s\n", le.ID, loadername,
|
||||
agtname,
|
||||
le.LastUsed.UTC().Format(time.RFC3339))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,6 +326,10 @@ func parseSearchQuery(orders []string) (p migdbsearch.Parameters, err error) {
|
|||
if err != nil {
|
||||
panic("invalid limit parameter")
|
||||
}
|
||||
case "loadername":
|
||||
p.LoaderName = value
|
||||
case "loaderid":
|
||||
p.LoaderID = value
|
||||
case "manifestname":
|
||||
p.ManifestName = value
|
||||
case "manifestid":
|
||||
|
|
|
@ -51,7 +51,9 @@ func (db *DB) UpdateLoaderEntry(lid float64, agt mig.Agent) (err error) {
|
|||
return
|
||||
}
|
||||
_, err = db.c.Exec(`UPDATE loaders
|
||||
SET name=$1, env=$2, tags=$3 WHERE id=$4`,
|
||||
SET name=$1, env=$2, tags=$3,
|
||||
lastused=now()
|
||||
WHERE id=$4`,
|
||||
agt.Name, jEnv, jTags, lid)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -103,7 +105,7 @@ func (db *DB) AllLoadersFromManifestID(mid float64) (ret []mig.LoaderEntry, err
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
qs := fmt.Sprintf("SELECT id, loadername, name FROM loaders WHERE %v", mtarg)
|
||||
qs := fmt.Sprintf("SELECT id, loadername, name, lastused FROM loaders WHERE %v", mtarg)
|
||||
rows, err := db.c.Query(qs)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -113,7 +115,7 @@ func (db *DB) AllLoadersFromManifestID(mid float64) (ret []mig.LoaderEntry, err
|
|||
}
|
||||
for rows.Next() {
|
||||
nle := mig.LoaderEntry{}
|
||||
err = rows.Scan(&nle.ID, &nle.Name, &nle.AgentName)
|
||||
err = rows.Scan(&nle.ID, &nle.Name, &nle.AgentName, &nle.LastUsed)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
|
|
@ -131,12 +131,13 @@ CREATE UNIQUE INDEX manifestsig_manifestid_investigatorid_idx ON manifestsig USI
|
|||
|
||||
CREATE SEQUENCE loaders_id_seq START 1;
|
||||
CREATE TABLE loaders (
|
||||
id numeric NOT NULL DEFAULT nextval('loaders_id_seq'),
|
||||
loadername character varying(256) NOT NULL,
|
||||
loaderkey character varying(64) NOT NULL,
|
||||
name character varying(2048),
|
||||
env json,
|
||||
tags json
|
||||
id numeric NOT NULL DEFAULT nextval('loaders_id_seq'),
|
||||
loadername character varying(256) NOT NULL,
|
||||
loaderkey character varying(64) NOT NULL,
|
||||
name character varying(2048),
|
||||
env json,
|
||||
tags json,
|
||||
lastused timestamp with time zone NOT NULL
|
||||
);
|
||||
ALTER TABLE ONLY loaders
|
||||
ADD CONSTRAINT loaders_pkey PRIMARY KEY (id);
|
||||
|
@ -202,7 +203,7 @@ GRANT INSERT ON actions, signatures, manifests, manifestsig TO migapi;
|
|||
GRANT DELETE ON manifestsig TO migapi;
|
||||
GRANT INSERT (name, pgpfingerprint, publickey, status, createdat, lastmodified) ON investigators TO migapi;
|
||||
GRANT UPDATE (status, lastmodified) ON investigators TO migapi;
|
||||
GRANT UPDATE (name, env, tags) ON loaders TO migapi;
|
||||
GRANT UPDATE (name, env, tags, lastused) ON loaders TO migapi;
|
||||
GRANT UPDATE (status) ON manifests TO migapi;
|
||||
GRANT USAGE ON SEQUENCE investigators_id_seq TO migapi;
|
||||
GRANT USAGE ON SEQUENCE loaders_id_seq TO migapi;
|
||||
|
|
|
@ -26,6 +26,8 @@ type Parameters struct {
|
|||
InvestigatorID string `json:"investigatorid"`
|
||||
InvestigatorName string `json:"investigatorname"`
|
||||
Limit float64 `json:"limit"`
|
||||
LoaderID string `json:"loaderid"`
|
||||
LoaderName string `json:"loadername"`
|
||||
ManifestID string `json:"manifestid"`
|
||||
ManifestName string `json:"manifestname"`
|
||||
Offset float64 `json:"offset"`
|
||||
|
@ -52,6 +54,8 @@ func NewParameters() (p Parameters) {
|
|||
p.InvestigatorID = "∞"
|
||||
p.InvestigatorName = "%"
|
||||
p.Limit = 100
|
||||
p.LoaderID = "∞"
|
||||
p.LoaderName = "%"
|
||||
p.ManifestID = "∞"
|
||||
p.ManifestName = "%"
|
||||
p.Offset = 0
|
||||
|
@ -88,6 +92,12 @@ func (p Parameters) String() (query string) {
|
|||
if p.InvestigatorName != "%" {
|
||||
query += fmt.Sprintf("&investigatorname=%s", p.InvestigatorName)
|
||||
}
|
||||
if p.LoaderID != "∞" {
|
||||
query += fmt.Sprintf("&loaderid=%s", p.LoaderID)
|
||||
}
|
||||
if p.LoaderName != "%" {
|
||||
query += fmt.Sprintf("&loadername=%s", p.LoaderName)
|
||||
}
|
||||
if p.ManifestName != "%" {
|
||||
query += fmt.Sprintf("&manifestname=%s", p.ManifestName)
|
||||
}
|
||||
|
|
|
@ -916,3 +916,84 @@ func (db *DB) SearchManifests(p search.Parameters) (mrecords []mig.ManifestRecor
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (db *DB) SearchLoaders(p search.Parameters) (lrecords []mig.LoaderEntry, err error) {
|
||||
var rows *sql.Rows
|
||||
ids, err := makeIDsFromParams(p)
|
||||
columns := `loaders.id, loaders.loadername, loaders.name, loaders.lastused`
|
||||
where := ""
|
||||
vals := []interface{}{}
|
||||
valctr := 0
|
||||
if p.Before.Before(time.Now().Add(search.DefaultWindow - time.Hour)) {
|
||||
where += fmt.Sprintf(`loaders.lastused <= $%d `, valctr+1)
|
||||
vals = append(vals, p.Before)
|
||||
valctr += 1
|
||||
}
|
||||
if p.After.After(time.Now().Add(-(search.DefaultWindow - time.Hour))) {
|
||||
if valctr > 0 {
|
||||
where += " AND "
|
||||
}
|
||||
where += fmt.Sprintf(`loaders.lastused >= $%d `, valctr+1)
|
||||
vals = append(vals, p.After)
|
||||
valctr += 1
|
||||
}
|
||||
if p.LoaderName != "%" {
|
||||
if valctr > 0 {
|
||||
where += " AND "
|
||||
}
|
||||
where += fmt.Sprintf(`loaders.loadername ILIKE $%d`, valctr+1)
|
||||
vals = append(vals, p.LoaderName)
|
||||
valctr += 1
|
||||
}
|
||||
if p.AgentName != "%" {
|
||||
if valctr > 0 {
|
||||
where += " AND "
|
||||
}
|
||||
where += fmt.Sprintf(`loaders.name ILIKE $%d`, valctr+1)
|
||||
vals = append(vals, p.AgentName)
|
||||
valctr += 1
|
||||
}
|
||||
if p.LoaderID != "∞" {
|
||||
if valctr > 0 {
|
||||
where += " AND "
|
||||
}
|
||||
where += fmt.Sprintf(`loaders.id >= $%d AND loaders.id <= $%d`,
|
||||
valctr+1, valctr+2)
|
||||
vals = append(vals, ids.minManID, ids.maxManID)
|
||||
valctr += 2
|
||||
}
|
||||
query := fmt.Sprintf(`SELECT %s FROM loaders WHERE %s ORDER BY loadername;`, columns, where)
|
||||
stmt, err := db.c.Prepare(query)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error while preparing search statement: '%v' in '%s'", err, query)
|
||||
return
|
||||
}
|
||||
if stmt != nil {
|
||||
defer stmt.Close()
|
||||
}
|
||||
rows, err = stmt.Query(vals...)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error while finding loaders: '%v'", err)
|
||||
}
|
||||
if rows != nil {
|
||||
defer rows.Close()
|
||||
}
|
||||
for rows.Next() {
|
||||
var le mig.LoaderEntry
|
||||
var agtnameNull sql.NullString
|
||||
err = rows.Scan(&le.ID, &le.Name, &agtnameNull, &le.LastUsed)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to retrieve loader data: '%v'", err)
|
||||
return
|
||||
}
|
||||
le.AgentName = "unset"
|
||||
if agtnameNull.Valid {
|
||||
le.AgentName = agtnameNull.String
|
||||
}
|
||||
lrecords = append(lrecords, le)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
err = fmt.Errorf("Failed to complete database query: '%v'", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
11
loader.go
11
loader.go
|
@ -6,9 +6,14 @@
|
|||
|
||||
package mig /* import "mig.ninja/mig" */
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Describes a loader entry stored in the database
|
||||
type LoaderEntry struct {
|
||||
ID float64 // Loader ID
|
||||
Name string // Loader name
|
||||
AgentName string // Loader environment, agent name
|
||||
ID float64 // Loader ID
|
||||
Name string // Loader name
|
||||
AgentName string // Loader environment, agent name
|
||||
LastUsed time.Time // Last time loader was used
|
||||
}
|
||||
|
|
|
@ -273,11 +273,13 @@ func manifestLoaders(respWriter http.ResponseWriter, request *http.Request) {
|
|||
respond(404, resource, respWriter, request)
|
||||
return
|
||||
}
|
||||
li, err := loaderEntrysToItem(ldrs, mid, ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
for _, ldr := range ldrs {
|
||||
item, err := loaderEntryToItem(ldr, mid, ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
resource.AddItem(item)
|
||||
}
|
||||
resource.AddItem(li)
|
||||
respond(200, resource, respWriter, request)
|
||||
}
|
||||
|
||||
|
@ -426,10 +428,11 @@ func manifestRecordToItem(mr mig.ManifestRecord, ctx Context) (item cljs.Item, e
|
|||
return
|
||||
}
|
||||
|
||||
func loaderEntrysToItem(ldrs []mig.LoaderEntry, mid float64, ctx Context) (item cljs.Item, err error) {
|
||||
func loaderEntryToItem(ldr mig.LoaderEntry, mid float64, ctx Context) (item cljs.Item, err error) {
|
||||
// XXX This Href doesn't properly represent the item and needs to be fixed
|
||||
item.Href = fmt.Sprintf("%s/manifest/loaders?manifestid=%.0f", ctx.Server.BaseURL, mid)
|
||||
item.Data = []cljs.Data{
|
||||
{Name: "loaders", Value: ldrs},
|
||||
{Name: "loader", Value: ldr},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ func search(respWriter http.ResponseWriter, request *http.Request) {
|
|||
results, err = ctx.DB.SearchInvestigators(p)
|
||||
case "manifest":
|
||||
results, err = ctx.DB.SearchManifests(p)
|
||||
case "loader":
|
||||
results, err = ctx.DB.SearchLoaders(p)
|
||||
default:
|
||||
panic("search type is invalid")
|
||||
}
|
||||
|
@ -218,6 +220,25 @@ func search(respWriter http.ResponseWriter, request *http.Request) {
|
|||
break
|
||||
}
|
||||
}
|
||||
case "loader":
|
||||
ctx.Channels.Log <- mig.Log{OpID: opid, Desc: fmt.Sprintf("returning search results with %d loaders", len(results.([]mig.LoaderEntry)))}
|
||||
if len(results.([]mig.LoaderEntry)) == 0 {
|
||||
panic("no results found")
|
||||
}
|
||||
for i, r := range results.([]mig.LoaderEntry) {
|
||||
err = resource.AddItem(cljs.Item{
|
||||
// XXX This should be an Href to fetch the entry
|
||||
Href: fmt.Sprintf("%s%s", ctx.Server.Host,
|
||||
ctx.Server.BaseRoute),
|
||||
Data: []cljs.Data{{Name: p.Type, Value: r}},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if float64(i) > p.Limit {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if needed, add pagination info
|
||||
|
@ -304,6 +325,10 @@ func parseSearchParameters(qp url.Values) (p migdbsearch.Parameters, filterFound
|
|||
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":
|
||||
|
|
Загрузка…
Ссылка в новой задаче