Skip to content

Commit

Permalink
Added an artifact search GUI
Browse files Browse the repository at this point in the history
Now artifacts are searched by keyword in the UI so we do not need to
rely on the name.
  • Loading branch information
scudette committed Apr 30, 2019
1 parent 75a586f commit 4b243f8
Show file tree
Hide file tree
Showing 24 changed files with 663 additions and 208 deletions.
27 changes: 10 additions & 17 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"fmt"
"net"
"net/http"
"strings"

"github.com/golang/protobuf/ptypes/empty"
"github.com/prometheus/client_golang/prometheus/promhttp"
Expand All @@ -38,7 +39,6 @@ import (
"google.golang.org/grpc/status"
actions_proto "www.velocidex.com/golang/velociraptor/actions/proto"
api_proto "www.velocidex.com/golang/velociraptor/api/proto"
artifacts "www.velocidex.com/golang/velociraptor/artifacts"
artifacts_proto "www.velocidex.com/golang/velociraptor/artifacts/proto"
"www.velocidex.com/golang/velociraptor/constants"
"www.velocidex.com/golang/velociraptor/datastore"
Expand Down Expand Up @@ -103,10 +103,12 @@ func (self *ApiServer) LaunchFlow(
ctx context.Context,
in *flows_proto.FlowRunnerArgs) (*api_proto.StartFlowResponse, error) {
result := &api_proto.StartFlowResponse{}
in.Creator = GetGRPCUserInfo(ctx).Name
creator := GetGRPCUserInfo(ctx).Name

// Internal calls from the frontend can set the creator.
if creator != constants.FRONTEND_NAME {
in.Creator = creator

// Empty creators are called internally.
if in.Creator != "" {
// If user is not found then reject it.
user_record, err := users.GetUser(self.config, in.Creator)
if err != nil {
Expand Down Expand Up @@ -491,19 +493,10 @@ func (self *ApiServer) GetArtifacts(
ctx context.Context,
in *api_proto.GetArtifactsRequest) (
*artifacts_proto.ArtifactDescriptors, error) {
result := &artifacts_proto.ArtifactDescriptors{}

repository, err := artifacts.GetGlobalRepository(self.config)
if err != nil {
return nil, err
}
for _, name := range repository.List() {
artifact, pres := repository.Get(name)
if pres {
result.Items = append(result.Items, artifact)
}
}
return result, nil
terms := strings.Split(in.SearchTerm, " ")
result, err := searchArtifact(
self.config, terms, in.Type, in.NumberOfResults)
return result, err
}

func (self *ApiServer) GetArtifactFile(
Expand Down
60 changes: 60 additions & 0 deletions api/artifacts.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"errors"
"path"
"regexp"
"strings"

actions_proto "www.velocidex.com/golang/velociraptor/actions/proto"
Expand Down Expand Up @@ -195,3 +196,62 @@ func renderBuiltinArtifacts(
},
}, nil
}

func searchArtifact(
config_obj *api_proto.Config,
terms []string,
artifact_type string,
number_of_results uint64) (
*artifacts_proto.ArtifactDescriptors, error) {

if number_of_results == 0 {
number_of_results = 100
}

result := &artifacts_proto.ArtifactDescriptors{}
regexes := []*regexp.Regexp{}
for _, term := range terms {
if len(term) <= 2 {
continue
}

re, err := regexp.Compile("(?i)" + term)
if err == nil {
regexes = append(regexes, re)
}
}

if len(regexes) == 0 {
return result, nil
}

matcher := func(text string, regexes []*regexp.Regexp) bool {
for _, re := range regexes {
if re.FindString(text) == "" {
return false
}
}
return true
}

repository, err := artifacts.GetGlobalRepository(config_obj)
if err != nil {
return nil, err
}

for _, name := range repository.List() {
artifact, pres := repository.Get(name)
if pres {
if matcher(artifact.Description, regexes) ||
matcher(artifact.Name, regexes) {
result.Items = append(result.Items, artifact)
}
}

if len(result.Items) >= int(number_of_results) {
break
}
}

return result, nil
}
27 changes: 22 additions & 5 deletions api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ import (
"encoding/json"
"net/http"

"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
api_proto "www.velocidex.com/golang/velociraptor/api/proto"
"www.velocidex.com/golang/velociraptor/constants"
"www.velocidex.com/golang/velociraptor/logging"
users "www.velocidex.com/golang/velociraptor/users"
)
Expand Down Expand Up @@ -107,12 +110,26 @@ func getClientApprovalForUser(
func GetGRPCUserInfo(ctx context.Context) *api_proto.VelociraptorUser {
result := &api_proto.VelociraptorUser{}

md, ok := metadata.FromIncomingContext(ctx)
peer, ok := peer.FromContext(ctx)
if ok {
userinfo := md.Get("USER")
if len(userinfo) > 0 {
data := []byte(userinfo[0])
json.Unmarshal(data, result)
tlsInfo, ok := peer.AuthInfo.(credentials.TLSInfo)
if ok {
v := tlsInfo.State.PeerCertificates[0].Subject.CommonName
// Calls from the gRPC gateway embed the
// authenticated web user in the metadata.
if v == constants.GRPC_GW_CLIENT_NAME {
md, ok := metadata.FromIncomingContext(ctx)
if ok {
userinfo := md.Get("USER")
if len(userinfo) > 0 {
data := []byte(userinfo[0])
json.Unmarshal(data, result)
}
}

} else {
result.Name = v
}
}
}

Expand Down
137 changes: 83 additions & 54 deletions api/proto/artifacts.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions api/proto/artifacts.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ import "www.velocidex.com/golang/velociraptor/actions/proto/vql.proto";
package proto;

message GetArtifactsRequest {
// Deprecated
bool include_event_artifacts = 1;
bool include_server_artifacts = 2;

string search_term = 3;
uint64 number_of_results = 4;
string type = 5;
}


message GetArtifactRequest {
// Deprecated.
string vfs_path = 1 [(sem_type) = {
description: "The vfs path relative to the artifacts definition store."
}];
Expand Down
Loading

0 comments on commit 4b243f8

Please sign in to comment.