From 4b5d2fd4ca4995019195288f0ae33b46c6fc9b9b Mon Sep 17 00:00:00 2001 From: Mike Cohen Date: Tue, 25 Apr 2023 01:19:02 +1000 Subject: [PATCH] Added a more complete text viewer implementation (#2641) New implementation includes paging and searching based on regex, string or hex data. This obsoletes the VFS text and hex views which are now removed. --- api/filesearch.go | 232 ++++++ api/mock/api_mock.go | 20 + api/proto/api.pb.go | 780 +++++++++--------- api/proto/api.pb.gw.go | 109 ++- api/proto/api.proto | 8 + api/proto/api_grpc.pb.go | 38 + api/proto/vfs_api.pb.go | 208 ++++- api/proto/vfs_api.proto | 27 + .../definitions/Server/Monitor/Health.yaml | 2 +- .../src/components/artifacts/artifacts.jsx | 6 +- .../bootstrap/pagination/PageItem.jsx | 93 --- .../components/bootstrap/pagination/index.jsx | 119 --- .../components/bootstrap/pagination/readme.md | 125 --- .../pagination/utils/getPagination.jsx | 73 -- .../bootstrap/pagination/utils/getStyles.jsx | 26 - .../src/components/core/api-service.jsx | 13 +- .../src/components/core/paged-table.jsx | 19 +- .../src/components/core/table.jsx | 12 + .../src/components/events/timeline-viewer.jsx | 6 +- .../src/components/flows/flow-uploads.jsx | 8 +- .../src/components/notebooks/downloads.jsx | 3 +- .../components/notebooks/export-notebook.jsx | 3 +- .../src/components/users/user-inspector.jsx | 39 +- .../src/components/users/user-label.jsx | 5 + .../src/components/utils/context.css | 4 + .../src/components/utils/context.jsx | 6 +- gui/velociraptor/src/components/utils/csv.jsx | 2 +- gui/velociraptor/src/components/utils/hex.css | 34 +- gui/velociraptor/src/components/utils/hex.jsx | 216 +++-- gui/velociraptor/src/components/utils/url.jsx | 8 +- .../src/components/vfs/browse-vfs.jsx | 5 +- .../src/components/vfs/file-details.jsx | 51 +- .../src/components/vfs/file-hex-view.css | 40 - .../src/components/vfs/file-hex-view.jsx | 213 ----- .../src/components/vfs/file-stats.jsx | 18 +- .../src/components/vfs/file-text-view.jsx | 146 ---- .../src/components/widgets/pagination.jsx | 111 +++ .../components/widgets/preview_uploads.css | 28 + .../components/widgets/preview_uploads.jsx | 143 ++-- .../src/components/widgets/search.css | 12 + .../src/components/widgets/search.jsx | 219 +++++ gui/velociraptor/src/css/_variables.css | 3 + gui/velociraptor/src/index.jsx | 5 +- gui/velociraptor/src/themes/veloci-light.css | 3 + vql/functions/unhex.go | 4 +- 45 files changed, 1792 insertions(+), 1453 deletions(-) create mode 100644 api/filesearch.go delete mode 100644 gui/velociraptor/src/components/bootstrap/pagination/PageItem.jsx delete mode 100644 gui/velociraptor/src/components/bootstrap/pagination/index.jsx delete mode 100644 gui/velociraptor/src/components/bootstrap/pagination/readme.md delete mode 100644 gui/velociraptor/src/components/bootstrap/pagination/utils/getPagination.jsx delete mode 100644 gui/velociraptor/src/components/bootstrap/pagination/utils/getStyles.jsx delete mode 100644 gui/velociraptor/src/components/vfs/file-hex-view.css delete mode 100644 gui/velociraptor/src/components/vfs/file-hex-view.jsx delete mode 100644 gui/velociraptor/src/components/vfs/file-text-view.jsx create mode 100644 gui/velociraptor/src/components/widgets/pagination.jsx create mode 100644 gui/velociraptor/src/components/widgets/search.css create mode 100644 gui/velociraptor/src/components/widgets/search.jsx diff --git a/api/filesearch.go b/api/filesearch.go new file mode 100644 index 00000000000..53b8837862a --- /dev/null +++ b/api/filesearch.go @@ -0,0 +1,232 @@ +package api + +import ( + "bytes" + "encoding/hex" + "io" + "regexp" + "strings" + + errors "github.com/go-errors/errors" + context "golang.org/x/net/context" + "www.velocidex.com/golang/velociraptor/acls" + api_proto "www.velocidex.com/golang/velociraptor/api/proto" + "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" + "www.velocidex.com/golang/velociraptor/services" + "www.velocidex.com/golang/velociraptor/uploads" + "www.velocidex.com/golang/velociraptor/utils" +) + +var ( + unsupportedSearchType = errors.New("Unsupported Search Type") +) + +func (self *ApiServer) SearchFile(ctx context.Context, + in *api_proto.SearchFileRequest) (*api_proto.SearchFileResponse, error) { + + users := services.GetUserManager() + user_record, org_config_obj, err := users.GetUserFromContext(ctx) + if err != nil { + return nil, Status(self.verbose, err) + } + + permissions := acls.READ_RESULTS + perm, err := services.CheckAccess(org_config_obj, user_record.Name, permissions) + if !perm || err != nil { + return nil, PermissionDenied(err, + "User is not allowed to search files.") + } + + if len(in.VfsComponents) == 0 { + return nil, PermissionDenied(err, "No file specified") + } + + matcher, err := newMatcher(in.Term, in.Type) + if err != nil { + return nil, Status(self.verbose, err) + } + + path_spec := path_specs.NewUnsafeFilestorePath(in.VfsComponents...). + SetType(api.PATH_TYPE_FILESTORE_ANY) + + file, err := file_store.GetFileStore(org_config_obj).ReadFile(path_spec) + if err != nil { + return nil, Status(self.verbose, err) + } + defer file.Close() + + var reader_at io.ReaderAt = utils.MakeReaderAtter(file) + index, err := getIndex(org_config_obj, path_spec) + + // If the file is sparse, we use the sparse reader. + if err == nil && in.Padding && len(index.Ranges) > 0 { + if !uploads.ShouldPadFile(org_config_obj, index) { + return nil, Status(self.verbose, errors.New( + "Sparse file is too sparse - unable to pad")) + } + + reader_at = &utils.RangedReader{ + ReaderAt: reader_at, + Index: index, + } + } + + offset := int64(in.Offset) + var buf []byte + + if in.Forward { + buf = pool.Get().([]byte) + defer pool.Put(buf) + + // To search backwards we need to rewind before the current + // offset. We may hit the start of the file, in which case we will + // get a smaller buffer. + } else { + base_offset := offset - BUFSIZE + + // The buffer is too small for the pool buffer - just allocate + // it from heap. + if base_offset < 0 { + buf = make([]byte, offset) + base_offset = 0 + + } else { + // Buffer is large enough so we can use the pool. + buf = pool.Get().([]byte) + defer pool.Put(buf) + } + + // Offset now reflects the start of the buffer. + offset = base_offset + } + + for { + // Allow for cancellations + select { + case <-ctx.Done(): + return &api_proto.SearchFileResponse{}, nil + default: + } + + n, err := reader_at.ReadAt(buf, offset) + if err != nil && err != io.EOF { + return nil, Status(self.verbose, err) + } + if n <= 0 { + return &api_proto.SearchFileResponse{}, nil + } + + if in.Forward { + hit := matcher.index(buf[:n]) + if hit >= 0 { + return &api_proto.SearchFileResponse{ + VfsComponents: in.VfsComponents, + Hit: uint64(hit + offset), + }, nil + } + offset += int64(n) + + } else { + hit := matcher.last_index(buf[:n]) + if hit >= 0 { + return &api_proto.SearchFileResponse{ + VfsComponents: in.VfsComponents, + Hit: uint64(hit + offset), + }, nil + } + offset -= int64(n) + + // Offset went backwards before the start of the file - we + // didnt find it. + if offset < 0 { + return &api_proto.SearchFileResponse{}, nil + } + } + } + + // No match + return &api_proto.SearchFileResponse{}, nil +} + +type matcher interface { + index(buff []byte) int64 + last_index(buff []byte) int64 +} + +type literal_matcher struct { + bytes []byte +} + +func (self *literal_matcher) index(buff []byte) int64 { + return int64(bytes.Index(buff, self.bytes)) +} + +func (self *literal_matcher) last_index(buff []byte) int64 { + return int64(bytes.LastIndex(buff, self.bytes)) +} + +type regex_matcher struct { + regex *regexp.Regexp +} + +func (self *regex_matcher) index(buff []byte) int64 { + match := self.regex.FindIndex(buff) + if len(match) == 0 { + return -1 + } + return int64(match[0]) +} + +// This is not super efficient for now because there is no easy way to +// regex search from the end. +func (self *regex_matcher) last_index(buff []byte) int64 { + matches := self.regex.FindAllIndex(buff, 1000) + if len(matches) == 0 { + return -1 + } + last_match := matches[len(matches)-1] + return int64(last_match[0]) +} + +type case_insensitive_matcher struct { + lower string +} + +func newMatcher(term, search_type string) (matcher, error) { + switch search_type { + case "", "string": + return &literal_matcher{[]byte(term)}, nil + + case "regex": + re, err := regexp.Compile("(?i)" + term) + if err != nil { + return nil, err + } + return ®ex_matcher{re}, nil + + case "hex": + str := strings.Replace(term, " ", "", -1) + + hex, err := hex.DecodeString(strings.TrimPrefix(str, "0x")) + if err != nil { + return nil, err + } + + // If the string has a 0x prefix, we assume it means a little + // endian integer so we need to reverse it. + if strings.HasPrefix(term, "0x") { + reversed := make([]byte, 0, len(hex)) + for i := len(hex) - 1; i >= 0; i-- { + reversed = append(reversed, hex[i]) + } + hex = reversed + } + + return &literal_matcher{hex}, nil + + default: + return nil, unsupportedSearchType + } +} diff --git a/api/mock/api_mock.go b/api/mock/api_mock.go index 7401188d55e..b3cb5ed98ac 100644 --- a/api/mock/api_mock.go +++ b/api/mock/api_mock.go @@ -1001,6 +1001,26 @@ func (mr *MockAPIClientMockRecorder) ReformatVQL(arg0, arg1 interface{}, arg2 .. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReformatVQL", reflect.TypeOf((*MockAPIClient)(nil).ReformatVQL), varargs...) } +// SearchFile mocks base method. +func (m *MockAPIClient) SearchFile(arg0 context.Context, arg1 *proto0.SearchFileRequest, arg2 ...grpc.CallOption) (*proto0.SearchFileResponse, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "SearchFile", varargs...) + ret0, _ := ret[0].(*proto0.SearchFileResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SearchFile indicates an expected call of SearchFile. +func (mr *MockAPIClientMockRecorder) SearchFile(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchFile", reflect.TypeOf((*MockAPIClient)(nil).SearchFile), varargs...) +} + // SetArtifactFile mocks base method. func (m *MockAPIClient) SetArtifactFile(arg0 context.Context, arg1 *proto0.SetArtifactRequest, arg2 ...grpc.CallOption) (*proto0.APIResponse, error) { m.ctrl.T.Helper() diff --git a/api/proto/api.pb.go b/api/proto/api.pb.go index e0baedc4532..70e4c38d60c 100644 --- a/api/proto/api.pb.go +++ b/api/proto/api.pb.go @@ -662,7 +662,7 @@ var file_api_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x72, 0x6f, 0x77, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x32, 0x95, 0x34, 0x0a, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x32, 0xf7, 0x34, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x52, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x75, 0x6e, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, @@ -849,241 +849,247 @@ var file_api_proto_rawDesc = []byte{ 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x54, 0x61, - 0x62, 0x6c, 0x65, 0x12, 0x75, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, + 0x62, 0x6c, 0x65, 0x12, 0x60, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, + 0x65, 0x12, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, + 0x6c, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x75, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x41, 0x72, 0x67, 0x73, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x41, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5c, 0x0a, 0x0a, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, - 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x3a, 0x01, 0x2a, 0x12, 0x5b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x46, - 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, + 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5c, 0x0a, 0x0a, + 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, - 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x67, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1f, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, - 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x71, - 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4b, - 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x63, 0x0a, 0x0b, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x56, 0x51, 0x4c, - 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x56, 0x51, 0x4c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x56, 0x51, 0x4c, 0x4d, - 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, - 0x56, 0x51, 0x4c, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, - 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x1f, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x12, - 0x69, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, - 0x6c, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x53, 0x65, - 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x50, 0x49, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, - 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, - 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x50, 0x61, 0x63, 0x6b, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, - 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, - 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x6f, 0x61, - 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x3a, 0x01, 0x2a, - 0x12, 0x44, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x1a, 0x0b, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x54, 0x6f, - 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x47, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, - 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, - 0x6f, 0x6c, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x22, - 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x3a, 0x01, 0x2a, 0x12, - 0x5c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x7a, 0x0a, - 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, + 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x3a, 0x01, 0x2a, 0x12, 0x5b, 0x0a, 0x0e, 0x47, 0x65, + 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x6f, 0x77, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, + 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, + 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x67, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, + 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, + 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, + 0x12, 0x71, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, - 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x22, - 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x18, 0x53, 0x65, - 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, + 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, + 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x25, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, + 0x74, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x63, 0x0a, 0x0b, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x56, + 0x51, 0x4c, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x66, 0x6f, 0x72, + 0x6d, 0x61, 0x74, 0x56, 0x51, 0x4c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x19, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x56, 0x51, + 0x4c, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, + 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x52, 0x65, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x56, 0x51, 0x4c, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, + 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x31, 0x2f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x3a, 0x01, + 0x2a, 0x12, 0x69, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x64, 0x0a, 0x0f, + 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, + 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x50, 0x49, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, + 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x3a, + 0x01, 0x2a, 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, + 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, + 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x3a, + 0x01, 0x2a, 0x12, 0x44, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x1a, 0x0b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x22, 0x1b, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, + 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x47, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x54, + 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x54, 0x6f, 0x6f, 0x6c, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, + 0x6c, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x3a, 0x01, + 0x2a, 0x12, 0x5c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, + 0x7a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, + 0x73, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x18, + 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x41, 0x72, 0x67, 0x73, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, - 0x67, 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, - 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, - 0x85, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, - 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, - 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x28, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, - 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, - 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x78, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x1a, 0x16, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, + 0x41, 0x72, 0x67, 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, - 0x2a, 0x12, 0x9c, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, - 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, + 0x2a, 0x12, 0x85, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x26, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, + 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, + 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x78, 0x0a, 0x18, 0x53, 0x65, 0x74, + 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x3a, 0x01, 0x2a, 0x12, 0x9c, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x21, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x3a, 0x01, 0x2a, - 0x12, 0x74, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, - 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, - 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, - 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, - 0x6b, 0x73, 0x12, 0x5f, 0x0a, 0x0b, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, - 0x6b, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, - 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, - 0x3a, 0x01, 0x2a, 0x12, 0x65, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, - 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, - 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, - 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0f, 0x4e, 0x65, - 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, - 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, - 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, - 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4e, - 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x6c, 0x0a, 0x12, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, - 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, - 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, - 0x6c, 0x6c, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, - 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x12, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, + 0x73, 0x12, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, + 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x21, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, + 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x3a, + 0x01, 0x2a, 0x12, 0x74, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, + 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, + 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, + 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x5f, 0x0a, 0x0b, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, + 0x6f, 0x6f, 0x6b, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, + 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x65, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, + 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0f, + 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, - 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, + 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x22, 0x1f, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, + 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x6c, 0x0a, + 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, + 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, + 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, + 0x43, 0x65, 0x6c, 0x6c, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, + 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x12, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, + 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, + 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, + 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, + 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x22, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, + 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, + 0x12, 0x8c, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, + 0x6f, 0x6f, 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, + 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, + 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, + 0x3c, 0x0a, 0x0c, 0x56, 0x46, 0x53, 0x47, 0x65, 0x74, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, + 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, + 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, + 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x22, 0x00, 0x12, 0x38, 0x0a, + 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, + 0x51, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, + 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x0a, 0x57, 0x61, 0x74, 0x63, 0x68, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x0a, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, - 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, 0x1a, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, 0x6f, 0x77, - 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0a, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, - 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x22, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, - 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x8c, - 0x01, 0x0a, 0x18, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, - 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, 0x6c, 0x65, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, - 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, - 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x3c, 0x0a, - 0x0c, 0x56, 0x46, 0x53, 0x47, 0x65, 0x74, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x14, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, - 0x66, 0x65, 0x72, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, - 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x05, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, - 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x12, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x0a, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x0a, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, - 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0a, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, - 0x37, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x53, - 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, - 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x12, 0x3d, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, - 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, - 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x19, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, 0x63, - 0x69, 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, - 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x00, 0x12, 0x37, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0a, 0x53, 0x65, + 0x74, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x75, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, + 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x00, 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, + 0x65, 0x6e, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x43, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x05, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x19, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, + 0x6f, 0x63, 0x69, 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, + 0x67, 0x2f, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1129,56 +1135,58 @@ var file_api_proto_goTypes = []interface{}{ (*SetPasswordRequest)(nil), // 26: proto.SetPasswordRequest (*VFSListRequest)(nil), // 27: proto.VFSListRequest (*VFSStatDownloadRequest)(nil), // 28: proto.VFSStatDownloadRequest - (*proto.ArtifactCollectorArgs)(nil), // 29: proto.ArtifactCollectorArgs - (*ReformatVQLMessage)(nil), // 30: proto.ReformatVQLMessage - (*GetArtifactsRequest)(nil), // 31: proto.GetArtifactsRequest - (*GetArtifactRequest)(nil), // 32: proto.GetArtifactRequest - (*SetArtifactRequest)(nil), // 33: proto.SetArtifactRequest - (*proto1.Tool)(nil), // 34: proto.Tool - (*GetReportRequest)(nil), // 35: proto.GetReportRequest - (*proto.GetClientMonitoringStateRequest)(nil), // 36: proto.GetClientMonitoringStateRequest - (*proto.ClientEventTable)(nil), // 37: proto.ClientEventTable - (*ListAvailableEventResultsRequest)(nil), // 38: proto.ListAvailableEventResultsRequest - (*CreateDownloadRequest)(nil), // 39: proto.CreateDownloadRequest - (*NotebookCellRequest)(nil), // 40: proto.NotebookCellRequest - (*NotebookMetadata)(nil), // 41: proto.NotebookMetadata - (*NotebookExportRequest)(nil), // 42: proto.NotebookExportRequest - (*NotebookFileUploadRequest)(nil), // 43: proto.NotebookFileUploadRequest - (*proto2.VQLCollectorArgs)(nil), // 44: proto.VQLCollectorArgs - (*proto2.VQLResponse)(nil), // 45: proto.VQLResponse - (*DataRequest)(nil), // 46: proto.DataRequest - (*HealthCheckRequest)(nil), // 47: proto.HealthCheckRequest - (*HuntStats)(nil), // 48: proto.HuntStats - (*ListHuntsResponse)(nil), // 49: proto.ListHuntsResponse - (*GetTableResponse)(nil), // 50: proto.GetTableResponse - (*APIResponse)(nil), // 51: proto.APIResponse - (*SearchClientsResponse)(nil), // 52: proto.SearchClientsResponse - (*ApiClient)(nil), // 53: proto.ApiClient - (*ClientMetadata)(nil), // 54: proto.ClientMetadata - (*ApiFlowResponse)(nil), // 55: proto.ApiFlowResponse - (*ApiUser)(nil), // 56: proto.ApiUser - (*SetGUIOptionsResponse)(nil), // 57: proto.SetGUIOptionsResponse - (*Users)(nil), // 58: proto.Users - (*VelociraptorUser)(nil), // 59: proto.VelociraptorUser - (*Favorites)(nil), // 60: proto.Favorites - (*VFSListResponse)(nil), // 61: proto.VFSListResponse - (*proto.ArtifactCollectorResponse)(nil), // 62: proto.ArtifactCollectorResponse - (*proto.VFSDownloadInfo)(nil), // 63: proto.VFSDownloadInfo - (*FlowDetails)(nil), // 64: proto.FlowDetails - (*ApiFlowRequestDetails)(nil), // 65: proto.ApiFlowRequestDetails - (*KeywordCompletions)(nil), // 66: proto.KeywordCompletions - (*proto1.ArtifactDescriptors)(nil), // 67: proto.ArtifactDescriptors - (*GetArtifactResponse)(nil), // 68: proto.GetArtifactResponse - (*LoadArtifactPackResponse)(nil), // 69: proto.LoadArtifactPackResponse - (*GetReportResponse)(nil), // 70: proto.GetReportResponse - (*ListAvailableEventResultsResponse)(nil), // 71: proto.ListAvailableEventResultsResponse - (*CreateDownloadResponse)(nil), // 72: proto.CreateDownloadResponse - (*Notebooks)(nil), // 73: proto.Notebooks - (*NotebookCell)(nil), // 74: proto.NotebookCell - (*NotebookFileUploadResponse)(nil), // 75: proto.NotebookFileUploadResponse - (*DataResponse)(nil), // 76: proto.DataResponse - (*ListChildrenResponse)(nil), // 77: proto.ListChildrenResponse - (*HealthCheckResponse)(nil), // 78: proto.HealthCheckResponse + (*SearchFileRequest)(nil), // 29: proto.SearchFileRequest + (*proto.ArtifactCollectorArgs)(nil), // 30: proto.ArtifactCollectorArgs + (*ReformatVQLMessage)(nil), // 31: proto.ReformatVQLMessage + (*GetArtifactsRequest)(nil), // 32: proto.GetArtifactsRequest + (*GetArtifactRequest)(nil), // 33: proto.GetArtifactRequest + (*SetArtifactRequest)(nil), // 34: proto.SetArtifactRequest + (*proto1.Tool)(nil), // 35: proto.Tool + (*GetReportRequest)(nil), // 36: proto.GetReportRequest + (*proto.GetClientMonitoringStateRequest)(nil), // 37: proto.GetClientMonitoringStateRequest + (*proto.ClientEventTable)(nil), // 38: proto.ClientEventTable + (*ListAvailableEventResultsRequest)(nil), // 39: proto.ListAvailableEventResultsRequest + (*CreateDownloadRequest)(nil), // 40: proto.CreateDownloadRequest + (*NotebookCellRequest)(nil), // 41: proto.NotebookCellRequest + (*NotebookMetadata)(nil), // 42: proto.NotebookMetadata + (*NotebookExportRequest)(nil), // 43: proto.NotebookExportRequest + (*NotebookFileUploadRequest)(nil), // 44: proto.NotebookFileUploadRequest + (*proto2.VQLCollectorArgs)(nil), // 45: proto.VQLCollectorArgs + (*proto2.VQLResponse)(nil), // 46: proto.VQLResponse + (*DataRequest)(nil), // 47: proto.DataRequest + (*HealthCheckRequest)(nil), // 48: proto.HealthCheckRequest + (*HuntStats)(nil), // 49: proto.HuntStats + (*ListHuntsResponse)(nil), // 50: proto.ListHuntsResponse + (*GetTableResponse)(nil), // 51: proto.GetTableResponse + (*APIResponse)(nil), // 52: proto.APIResponse + (*SearchClientsResponse)(nil), // 53: proto.SearchClientsResponse + (*ApiClient)(nil), // 54: proto.ApiClient + (*ClientMetadata)(nil), // 55: proto.ClientMetadata + (*ApiFlowResponse)(nil), // 56: proto.ApiFlowResponse + (*ApiUser)(nil), // 57: proto.ApiUser + (*SetGUIOptionsResponse)(nil), // 58: proto.SetGUIOptionsResponse + (*Users)(nil), // 59: proto.Users + (*VelociraptorUser)(nil), // 60: proto.VelociraptorUser + (*Favorites)(nil), // 61: proto.Favorites + (*VFSListResponse)(nil), // 62: proto.VFSListResponse + (*proto.ArtifactCollectorResponse)(nil), // 63: proto.ArtifactCollectorResponse + (*proto.VFSDownloadInfo)(nil), // 64: proto.VFSDownloadInfo + (*SearchFileResponse)(nil), // 65: proto.SearchFileResponse + (*FlowDetails)(nil), // 66: proto.FlowDetails + (*ApiFlowRequestDetails)(nil), // 67: proto.ApiFlowRequestDetails + (*KeywordCompletions)(nil), // 68: proto.KeywordCompletions + (*proto1.ArtifactDescriptors)(nil), // 69: proto.ArtifactDescriptors + (*GetArtifactResponse)(nil), // 70: proto.GetArtifactResponse + (*LoadArtifactPackResponse)(nil), // 71: proto.LoadArtifactPackResponse + (*GetReportResponse)(nil), // 72: proto.GetReportResponse + (*ListAvailableEventResultsResponse)(nil), // 73: proto.ListAvailableEventResultsResponse + (*CreateDownloadResponse)(nil), // 74: proto.CreateDownloadResponse + (*Notebooks)(nil), // 75: proto.Notebooks + (*NotebookCell)(nil), // 76: proto.NotebookCell + (*NotebookFileUploadResponse)(nil), // 77: proto.NotebookFileUploadResponse + (*DataResponse)(nil), // 78: proto.DataResponse + (*ListChildrenResponse)(nil), // 79: proto.ListChildrenResponse + (*HealthCheckResponse)(nil), // 80: proto.HealthCheckResponse } var file_api_proto_depIdxs = []int32{ 1, // 0: proto.ApprovalList.items:type_name -> proto.Approval @@ -1212,114 +1220,116 @@ var file_api_proto_depIdxs = []int32{ 27, // 28: proto.API.VFSStatDirectory:input_type -> proto.VFSListRequest 28, // 29: proto.API.VFSStatDownload:input_type -> proto.VFSStatDownloadRequest 13, // 30: proto.API.GetTable:input_type -> proto.GetTableRequest - 29, // 31: proto.API.CollectArtifact:input_type -> proto.ArtifactCollectorArgs - 19, // 32: proto.API.CancelFlow:input_type -> proto.ApiFlowRequest - 19, // 33: proto.API.GetFlowDetails:input_type -> proto.ApiFlowRequest - 19, // 34: proto.API.GetFlowRequests:input_type -> proto.ApiFlowRequest - 20, // 35: proto.API.GetKeywordCompletions:input_type -> google.protobuf.Empty - 30, // 36: proto.API.ReformatVQL:input_type -> proto.ReformatVQLMessage - 31, // 37: proto.API.GetArtifacts:input_type -> proto.GetArtifactsRequest - 32, // 38: proto.API.GetArtifactFile:input_type -> proto.GetArtifactRequest - 33, // 39: proto.API.SetArtifactFile:input_type -> proto.SetArtifactRequest - 4, // 40: proto.API.LoadArtifactPack:input_type -> proto.VFSFileBuffer - 34, // 41: proto.API.GetToolInfo:input_type -> proto.Tool - 34, // 42: proto.API.SetToolInfo:input_type -> proto.Tool - 35, // 43: proto.API.GetReport:input_type -> proto.GetReportRequest - 20, // 44: proto.API.GetServerMonitoringState:input_type -> google.protobuf.Empty - 29, // 45: proto.API.SetServerMonitoringState:input_type -> proto.ArtifactCollectorArgs - 36, // 46: proto.API.GetClientMonitoringState:input_type -> proto.GetClientMonitoringStateRequest - 37, // 47: proto.API.SetClientMonitoringState:input_type -> proto.ClientEventTable - 38, // 48: proto.API.ListAvailableEventResults:input_type -> proto.ListAvailableEventResultsRequest - 39, // 49: proto.API.CreateDownloadFile:input_type -> proto.CreateDownloadRequest - 40, // 50: proto.API.GetNotebooks:input_type -> proto.NotebookCellRequest - 41, // 51: proto.API.NewNotebook:input_type -> proto.NotebookMetadata - 41, // 52: proto.API.UpdateNotebook:input_type -> proto.NotebookMetadata - 40, // 53: proto.API.NewNotebookCell:input_type -> proto.NotebookCellRequest - 40, // 54: proto.API.GetNotebookCell:input_type -> proto.NotebookCellRequest - 40, // 55: proto.API.UpdateNotebookCell:input_type -> proto.NotebookCellRequest - 40, // 56: proto.API.CancelNotebookCell:input_type -> proto.NotebookCellRequest - 42, // 57: proto.API.CreateNotebookDownloadFile:input_type -> proto.NotebookExportRequest - 43, // 58: proto.API.UploadNotebookAttachment:input_type -> proto.NotebookFileUploadRequest - 4, // 59: proto.API.VFSGetBuffer:input_type -> proto.VFSFileBuffer - 44, // 60: proto.API.Query:input_type -> proto.VQLCollectorArgs - 6, // 61: proto.API.WatchEvent:input_type -> proto.EventRequest - 8, // 62: proto.API.PushEvents:input_type -> proto.PushEventRequest - 45, // 63: proto.API.WriteEvent:input_type -> proto.VQLResponse - 46, // 64: proto.API.GetSubject:input_type -> proto.DataRequest - 46, // 65: proto.API.SetSubject:input_type -> proto.DataRequest - 46, // 66: proto.API.DeleteSubject:input_type -> proto.DataRequest - 46, // 67: proto.API.ListChildren:input_type -> proto.DataRequest - 47, // 68: proto.API.Check:input_type -> proto.HealthCheckRequest - 0, // 69: proto.API.CreateHunt:output_type -> proto.StartFlowResponse - 48, // 70: proto.API.EstimateHunt:output_type -> proto.HuntStats - 49, // 71: proto.API.ListHunts:output_type -> proto.ListHuntsResponse - 9, // 72: proto.API.GetHunt:output_type -> proto.Hunt - 20, // 73: proto.API.ModifyHunt:output_type -> google.protobuf.Empty - 50, // 74: proto.API.GetHuntFlows:output_type -> proto.GetTableResponse - 50, // 75: proto.API.GetHuntResults:output_type -> proto.GetTableResponse - 20, // 76: proto.API.NotifyClients:output_type -> google.protobuf.Empty - 51, // 77: proto.API.LabelClients:output_type -> proto.APIResponse - 52, // 78: proto.API.ListClients:output_type -> proto.SearchClientsResponse - 53, // 79: proto.API.GetClient:output_type -> proto.ApiClient - 54, // 80: proto.API.GetClientMetadata:output_type -> proto.ClientMetadata - 20, // 81: proto.API.SetClientMetadata:output_type -> google.protobuf.Empty - 55, // 82: proto.API.GetClientFlows:output_type -> proto.ApiFlowResponse - 56, // 83: proto.API.GetUserUITraits:output_type -> proto.ApiUser - 57, // 84: proto.API.SetGUIOptions:output_type -> proto.SetGUIOptionsResponse - 58, // 85: proto.API.GetUsers:output_type -> proto.Users - 58, // 86: proto.API.GetGlobalUsers:output_type -> proto.Users - 23, // 87: proto.API.GetUserRoles:output_type -> proto.UserRoles - 20, // 88: proto.API.SetUserRoles:output_type -> google.protobuf.Empty - 59, // 89: proto.API.GetUser:output_type -> proto.VelociraptorUser - 20, // 90: proto.API.CreateUser:output_type -> google.protobuf.Empty - 60, // 91: proto.API.GetUserFavorites:output_type -> proto.Favorites - 20, // 92: proto.API.SetPassword:output_type -> google.protobuf.Empty - 61, // 93: proto.API.VFSListDirectory:output_type -> proto.VFSListResponse - 50, // 94: proto.API.VFSListDirectoryFiles:output_type -> proto.GetTableResponse - 62, // 95: proto.API.VFSRefreshDirectory:output_type -> proto.ArtifactCollectorResponse - 61, // 96: proto.API.VFSStatDirectory:output_type -> proto.VFSListResponse - 63, // 97: proto.API.VFSStatDownload:output_type -> proto.VFSDownloadInfo - 50, // 98: proto.API.GetTable:output_type -> proto.GetTableResponse - 62, // 99: proto.API.CollectArtifact:output_type -> proto.ArtifactCollectorResponse - 0, // 100: proto.API.CancelFlow:output_type -> proto.StartFlowResponse - 64, // 101: proto.API.GetFlowDetails:output_type -> proto.FlowDetails - 65, // 102: proto.API.GetFlowRequests:output_type -> proto.ApiFlowRequestDetails - 66, // 103: proto.API.GetKeywordCompletions:output_type -> proto.KeywordCompletions - 30, // 104: proto.API.ReformatVQL:output_type -> proto.ReformatVQLMessage - 67, // 105: proto.API.GetArtifacts:output_type -> proto.ArtifactDescriptors - 68, // 106: proto.API.GetArtifactFile:output_type -> proto.GetArtifactResponse - 51, // 107: proto.API.SetArtifactFile:output_type -> proto.APIResponse - 69, // 108: proto.API.LoadArtifactPack:output_type -> proto.LoadArtifactPackResponse - 34, // 109: proto.API.GetToolInfo:output_type -> proto.Tool - 34, // 110: proto.API.SetToolInfo:output_type -> proto.Tool - 70, // 111: proto.API.GetReport:output_type -> proto.GetReportResponse - 29, // 112: proto.API.GetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs - 29, // 113: proto.API.SetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs - 37, // 114: proto.API.GetClientMonitoringState:output_type -> proto.ClientEventTable - 20, // 115: proto.API.SetClientMonitoringState:output_type -> google.protobuf.Empty - 71, // 116: proto.API.ListAvailableEventResults:output_type -> proto.ListAvailableEventResultsResponse - 72, // 117: proto.API.CreateDownloadFile:output_type -> proto.CreateDownloadResponse - 73, // 118: proto.API.GetNotebooks:output_type -> proto.Notebooks - 41, // 119: proto.API.NewNotebook:output_type -> proto.NotebookMetadata - 41, // 120: proto.API.UpdateNotebook:output_type -> proto.NotebookMetadata - 41, // 121: proto.API.NewNotebookCell:output_type -> proto.NotebookMetadata - 74, // 122: proto.API.GetNotebookCell:output_type -> proto.NotebookCell - 74, // 123: proto.API.UpdateNotebookCell:output_type -> proto.NotebookCell - 20, // 124: proto.API.CancelNotebookCell:output_type -> google.protobuf.Empty - 20, // 125: proto.API.CreateNotebookDownloadFile:output_type -> google.protobuf.Empty - 75, // 126: proto.API.UploadNotebookAttachment:output_type -> proto.NotebookFileUploadResponse - 4, // 127: proto.API.VFSGetBuffer:output_type -> proto.VFSFileBuffer - 45, // 128: proto.API.Query:output_type -> proto.VQLResponse - 7, // 129: proto.API.WatchEvent:output_type -> proto.EventResponse - 20, // 130: proto.API.PushEvents:output_type -> google.protobuf.Empty - 20, // 131: proto.API.WriteEvent:output_type -> google.protobuf.Empty - 76, // 132: proto.API.GetSubject:output_type -> proto.DataResponse - 76, // 133: proto.API.SetSubject:output_type -> proto.DataResponse - 20, // 134: proto.API.DeleteSubject:output_type -> google.protobuf.Empty - 77, // 135: proto.API.ListChildren:output_type -> proto.ListChildrenResponse - 78, // 136: proto.API.Check:output_type -> proto.HealthCheckResponse - 69, // [69:137] is the sub-list for method output_type - 1, // [1:69] is the sub-list for method input_type + 29, // 31: proto.API.SearchFile:input_type -> proto.SearchFileRequest + 30, // 32: proto.API.CollectArtifact:input_type -> proto.ArtifactCollectorArgs + 19, // 33: proto.API.CancelFlow:input_type -> proto.ApiFlowRequest + 19, // 34: proto.API.GetFlowDetails:input_type -> proto.ApiFlowRequest + 19, // 35: proto.API.GetFlowRequests:input_type -> proto.ApiFlowRequest + 20, // 36: proto.API.GetKeywordCompletions:input_type -> google.protobuf.Empty + 31, // 37: proto.API.ReformatVQL:input_type -> proto.ReformatVQLMessage + 32, // 38: proto.API.GetArtifacts:input_type -> proto.GetArtifactsRequest + 33, // 39: proto.API.GetArtifactFile:input_type -> proto.GetArtifactRequest + 34, // 40: proto.API.SetArtifactFile:input_type -> proto.SetArtifactRequest + 4, // 41: proto.API.LoadArtifactPack:input_type -> proto.VFSFileBuffer + 35, // 42: proto.API.GetToolInfo:input_type -> proto.Tool + 35, // 43: proto.API.SetToolInfo:input_type -> proto.Tool + 36, // 44: proto.API.GetReport:input_type -> proto.GetReportRequest + 20, // 45: proto.API.GetServerMonitoringState:input_type -> google.protobuf.Empty + 30, // 46: proto.API.SetServerMonitoringState:input_type -> proto.ArtifactCollectorArgs + 37, // 47: proto.API.GetClientMonitoringState:input_type -> proto.GetClientMonitoringStateRequest + 38, // 48: proto.API.SetClientMonitoringState:input_type -> proto.ClientEventTable + 39, // 49: proto.API.ListAvailableEventResults:input_type -> proto.ListAvailableEventResultsRequest + 40, // 50: proto.API.CreateDownloadFile:input_type -> proto.CreateDownloadRequest + 41, // 51: proto.API.GetNotebooks:input_type -> proto.NotebookCellRequest + 42, // 52: proto.API.NewNotebook:input_type -> proto.NotebookMetadata + 42, // 53: proto.API.UpdateNotebook:input_type -> proto.NotebookMetadata + 41, // 54: proto.API.NewNotebookCell:input_type -> proto.NotebookCellRequest + 41, // 55: proto.API.GetNotebookCell:input_type -> proto.NotebookCellRequest + 41, // 56: proto.API.UpdateNotebookCell:input_type -> proto.NotebookCellRequest + 41, // 57: proto.API.CancelNotebookCell:input_type -> proto.NotebookCellRequest + 43, // 58: proto.API.CreateNotebookDownloadFile:input_type -> proto.NotebookExportRequest + 44, // 59: proto.API.UploadNotebookAttachment:input_type -> proto.NotebookFileUploadRequest + 4, // 60: proto.API.VFSGetBuffer:input_type -> proto.VFSFileBuffer + 45, // 61: proto.API.Query:input_type -> proto.VQLCollectorArgs + 6, // 62: proto.API.WatchEvent:input_type -> proto.EventRequest + 8, // 63: proto.API.PushEvents:input_type -> proto.PushEventRequest + 46, // 64: proto.API.WriteEvent:input_type -> proto.VQLResponse + 47, // 65: proto.API.GetSubject:input_type -> proto.DataRequest + 47, // 66: proto.API.SetSubject:input_type -> proto.DataRequest + 47, // 67: proto.API.DeleteSubject:input_type -> proto.DataRequest + 47, // 68: proto.API.ListChildren:input_type -> proto.DataRequest + 48, // 69: proto.API.Check:input_type -> proto.HealthCheckRequest + 0, // 70: proto.API.CreateHunt:output_type -> proto.StartFlowResponse + 49, // 71: proto.API.EstimateHunt:output_type -> proto.HuntStats + 50, // 72: proto.API.ListHunts:output_type -> proto.ListHuntsResponse + 9, // 73: proto.API.GetHunt:output_type -> proto.Hunt + 20, // 74: proto.API.ModifyHunt:output_type -> google.protobuf.Empty + 51, // 75: proto.API.GetHuntFlows:output_type -> proto.GetTableResponse + 51, // 76: proto.API.GetHuntResults:output_type -> proto.GetTableResponse + 20, // 77: proto.API.NotifyClients:output_type -> google.protobuf.Empty + 52, // 78: proto.API.LabelClients:output_type -> proto.APIResponse + 53, // 79: proto.API.ListClients:output_type -> proto.SearchClientsResponse + 54, // 80: proto.API.GetClient:output_type -> proto.ApiClient + 55, // 81: proto.API.GetClientMetadata:output_type -> proto.ClientMetadata + 20, // 82: proto.API.SetClientMetadata:output_type -> google.protobuf.Empty + 56, // 83: proto.API.GetClientFlows:output_type -> proto.ApiFlowResponse + 57, // 84: proto.API.GetUserUITraits:output_type -> proto.ApiUser + 58, // 85: proto.API.SetGUIOptions:output_type -> proto.SetGUIOptionsResponse + 59, // 86: proto.API.GetUsers:output_type -> proto.Users + 59, // 87: proto.API.GetGlobalUsers:output_type -> proto.Users + 23, // 88: proto.API.GetUserRoles:output_type -> proto.UserRoles + 20, // 89: proto.API.SetUserRoles:output_type -> google.protobuf.Empty + 60, // 90: proto.API.GetUser:output_type -> proto.VelociraptorUser + 20, // 91: proto.API.CreateUser:output_type -> google.protobuf.Empty + 61, // 92: proto.API.GetUserFavorites:output_type -> proto.Favorites + 20, // 93: proto.API.SetPassword:output_type -> google.protobuf.Empty + 62, // 94: proto.API.VFSListDirectory:output_type -> proto.VFSListResponse + 51, // 95: proto.API.VFSListDirectoryFiles:output_type -> proto.GetTableResponse + 63, // 96: proto.API.VFSRefreshDirectory:output_type -> proto.ArtifactCollectorResponse + 62, // 97: proto.API.VFSStatDirectory:output_type -> proto.VFSListResponse + 64, // 98: proto.API.VFSStatDownload:output_type -> proto.VFSDownloadInfo + 51, // 99: proto.API.GetTable:output_type -> proto.GetTableResponse + 65, // 100: proto.API.SearchFile:output_type -> proto.SearchFileResponse + 63, // 101: proto.API.CollectArtifact:output_type -> proto.ArtifactCollectorResponse + 0, // 102: proto.API.CancelFlow:output_type -> proto.StartFlowResponse + 66, // 103: proto.API.GetFlowDetails:output_type -> proto.FlowDetails + 67, // 104: proto.API.GetFlowRequests:output_type -> proto.ApiFlowRequestDetails + 68, // 105: proto.API.GetKeywordCompletions:output_type -> proto.KeywordCompletions + 31, // 106: proto.API.ReformatVQL:output_type -> proto.ReformatVQLMessage + 69, // 107: proto.API.GetArtifacts:output_type -> proto.ArtifactDescriptors + 70, // 108: proto.API.GetArtifactFile:output_type -> proto.GetArtifactResponse + 52, // 109: proto.API.SetArtifactFile:output_type -> proto.APIResponse + 71, // 110: proto.API.LoadArtifactPack:output_type -> proto.LoadArtifactPackResponse + 35, // 111: proto.API.GetToolInfo:output_type -> proto.Tool + 35, // 112: proto.API.SetToolInfo:output_type -> proto.Tool + 72, // 113: proto.API.GetReport:output_type -> proto.GetReportResponse + 30, // 114: proto.API.GetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs + 30, // 115: proto.API.SetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs + 38, // 116: proto.API.GetClientMonitoringState:output_type -> proto.ClientEventTable + 20, // 117: proto.API.SetClientMonitoringState:output_type -> google.protobuf.Empty + 73, // 118: proto.API.ListAvailableEventResults:output_type -> proto.ListAvailableEventResultsResponse + 74, // 119: proto.API.CreateDownloadFile:output_type -> proto.CreateDownloadResponse + 75, // 120: proto.API.GetNotebooks:output_type -> proto.Notebooks + 42, // 121: proto.API.NewNotebook:output_type -> proto.NotebookMetadata + 42, // 122: proto.API.UpdateNotebook:output_type -> proto.NotebookMetadata + 42, // 123: proto.API.NewNotebookCell:output_type -> proto.NotebookMetadata + 76, // 124: proto.API.GetNotebookCell:output_type -> proto.NotebookCell + 76, // 125: proto.API.UpdateNotebookCell:output_type -> proto.NotebookCell + 20, // 126: proto.API.CancelNotebookCell:output_type -> google.protobuf.Empty + 20, // 127: proto.API.CreateNotebookDownloadFile:output_type -> google.protobuf.Empty + 77, // 128: proto.API.UploadNotebookAttachment:output_type -> proto.NotebookFileUploadResponse + 4, // 129: proto.API.VFSGetBuffer:output_type -> proto.VFSFileBuffer + 46, // 130: proto.API.Query:output_type -> proto.VQLResponse + 7, // 131: proto.API.WatchEvent:output_type -> proto.EventResponse + 20, // 132: proto.API.PushEvents:output_type -> google.protobuf.Empty + 20, // 133: proto.API.WriteEvent:output_type -> google.protobuf.Empty + 78, // 134: proto.API.GetSubject:output_type -> proto.DataResponse + 78, // 135: proto.API.SetSubject:output_type -> proto.DataResponse + 20, // 136: proto.API.DeleteSubject:output_type -> google.protobuf.Empty + 79, // 137: proto.API.ListChildren:output_type -> proto.ListChildrenResponse + 80, // 138: proto.API.Check:output_type -> proto.HealthCheckResponse + 70, // [70:139] is the sub-list for method output_type + 1, // [1:70] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name diff --git a/api/proto/api.pb.gw.go b/api/proto/api.pb.gw.go index 76147407558..168f9e3646a 100644 --- a/api/proto/api.pb.gw.go +++ b/api/proto/api.pb.gw.go @@ -22,8 +22,8 @@ import ( "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" - proto_0 "www.velocidex.com/golang/velociraptor/artifacts/proto" - proto_7 "www.velocidex.com/golang/velociraptor/flows/proto" + proto_1 "www.velocidex.com/golang/velociraptor/artifacts/proto" + proto_2 "www.velocidex.com/golang/velociraptor/flows/proto" ) // Suppress "imported and not used" errors @@ -1278,8 +1278,42 @@ func local_request_API_GetTable_0(ctx context.Context, marshaler runtime.Marshal } +func request_API_SearchFile_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SearchFileRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SearchFile(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_API_SearchFile_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq SearchFileRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SearchFile(ctx, &protoReq) + return msg, metadata, err + +} + func request_API_CollectArtifact_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.ArtifactCollectorArgs + var protoReq proto_2.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1296,7 +1330,7 @@ func request_API_CollectArtifact_0(ctx context.Context, marshaler runtime.Marsha } func local_request_API_CollectArtifact_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.ArtifactCollectorArgs + var protoReq proto_2.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1613,7 +1647,7 @@ var ( ) func request_API_GetToolInfo_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_0.Tool + var protoReq proto_1.Tool var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1629,7 +1663,7 @@ func request_API_GetToolInfo_0(ctx context.Context, marshaler runtime.Marshaler, } func local_request_API_GetToolInfo_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_0.Tool + var protoReq proto_1.Tool var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1645,7 +1679,7 @@ func local_request_API_GetToolInfo_0(ctx context.Context, marshaler runtime.Mars } func request_API_SetToolInfo_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_0.Tool + var protoReq proto_1.Tool var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1662,7 +1696,7 @@ func request_API_SetToolInfo_0(ctx context.Context, marshaler runtime.Marshaler, } func local_request_API_SetToolInfo_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_0.Tool + var protoReq proto_1.Tool var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1731,7 +1765,7 @@ func local_request_API_GetServerMonitoringState_0(ctx context.Context, marshaler } func request_API_SetServerMonitoringState_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.ArtifactCollectorArgs + var protoReq proto_2.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1748,7 +1782,7 @@ func request_API_SetServerMonitoringState_0(ctx context.Context, marshaler runti } func local_request_API_SetServerMonitoringState_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.ArtifactCollectorArgs + var protoReq proto_2.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1769,7 +1803,7 @@ var ( ) func request_API_GetClientMonitoringState_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.GetClientMonitoringStateRequest + var protoReq proto_2.GetClientMonitoringStateRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1785,7 +1819,7 @@ func request_API_GetClientMonitoringState_0(ctx context.Context, marshaler runti } func local_request_API_GetClientMonitoringState_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.GetClientMonitoringStateRequest + var protoReq proto_2.GetClientMonitoringStateRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1801,7 +1835,7 @@ func local_request_API_GetClientMonitoringState_0(ctx context.Context, marshaler } func request_API_SetClientMonitoringState_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.ClientEventTable + var protoReq proto_2.ClientEventTable var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1818,7 +1852,7 @@ func request_API_SetClientMonitoringState_0(ctx context.Context, marshaler runti } func local_request_API_SetClientMonitoringState_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_7.ClientEventTable + var protoReq proto_2.ClientEventTable var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -2931,6 +2965,29 @@ func RegisterAPIHandlerServer(ctx context.Context, mux *runtime.ServeMux, server }) + mux.Handle("POST", pattern_API_SearchFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/proto.API/SearchFile", runtime.WithHTTPPathPattern("/api/v1/SearchFile")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_API_SearchFile_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_API_SearchFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_API_CollectArtifact_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -4236,6 +4293,26 @@ func RegisterAPIHandlerClient(ctx context.Context, mux *runtime.ServeMux, client }) + mux.Handle("POST", pattern_API_SearchFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/proto.API/SearchFile", runtime.WithHTTPPathPattern("/api/v1/SearchFile")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_API_SearchFile_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_API_SearchFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_API_CollectArtifact_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -4862,6 +4939,8 @@ var ( pattern_API_GetTable_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "GetTable"}, "")) + pattern_API_SearchFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "SearchFile"}, "")) + pattern_API_CollectArtifact_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "CollectArtifact"}, "")) pattern_API_CancelFlow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "CancelFlow"}, "")) @@ -4982,6 +5061,8 @@ var ( forward_API_GetTable_0 = runtime.ForwardResponseMessage + forward_API_SearchFile_0 = runtime.ForwardResponseMessage + forward_API_CollectArtifact_0 = runtime.ForwardResponseMessage forward_API_CancelFlow_0 = runtime.ForwardResponseMessage diff --git a/api/proto/api.proto b/api/proto/api.proto index 43bc18b0e5a..8ec0fa35dc9 100644 --- a/api/proto/api.proto +++ b/api/proto/api.proto @@ -307,6 +307,14 @@ service API { }; } + // Facilitate the HexEditor search API + rpc SearchFile(SearchFileRequest) returns (SearchFileResponse) { + option (google.api.http) = { + post: "/api/v1/SearchFile", + body: "*", + }; + } + // Flows rpc CollectArtifact(ArtifactCollectorArgs) returns (ArtifactCollectorResponse) { option (google.api.http) = { diff --git a/api/proto/api_grpc.pb.go b/api/proto/api_grpc.pb.go index f0ce53e4479..9c421cb2274 100644 --- a/api/proto/api_grpc.pb.go +++ b/api/proto/api_grpc.pb.go @@ -60,6 +60,8 @@ type APIClient interface { VFSStatDirectory(ctx context.Context, in *VFSListRequest, opts ...grpc.CallOption) (*VFSListResponse, error) VFSStatDownload(ctx context.Context, in *VFSStatDownloadRequest, opts ...grpc.CallOption) (*proto.VFSDownloadInfo, error) GetTable(ctx context.Context, in *GetTableRequest, opts ...grpc.CallOption) (*GetTableResponse, error) + // Facilitate the HexEditor search API + SearchFile(ctx context.Context, in *SearchFileRequest, opts ...grpc.CallOption) (*SearchFileResponse, error) // Flows CollectArtifact(ctx context.Context, in *proto.ArtifactCollectorArgs, opts ...grpc.CallOption) (*proto.ArtifactCollectorResponse, error) CancelFlow(ctx context.Context, in *ApiFlowRequest, opts ...grpc.CallOption) (*StartFlowResponse, error) @@ -400,6 +402,15 @@ func (c *aPIClient) GetTable(ctx context.Context, in *GetTableRequest, opts ...g return out, nil } +func (c *aPIClient) SearchFile(ctx context.Context, in *SearchFileRequest, opts ...grpc.CallOption) (*SearchFileResponse, error) { + out := new(SearchFileResponse) + err := c.cc.Invoke(ctx, "/proto.API/SearchFile", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *aPIClient) CollectArtifact(ctx context.Context, in *proto.ArtifactCollectorArgs, opts ...grpc.CallOption) (*proto.ArtifactCollectorResponse, error) { out := new(proto.ArtifactCollectorResponse) err := c.cc.Invoke(ctx, "/proto.API/CollectArtifact", in, out, opts...) @@ -830,6 +841,8 @@ type APIServer interface { VFSStatDirectory(context.Context, *VFSListRequest) (*VFSListResponse, error) VFSStatDownload(context.Context, *VFSStatDownloadRequest) (*proto.VFSDownloadInfo, error) GetTable(context.Context, *GetTableRequest) (*GetTableResponse, error) + // Facilitate the HexEditor search API + SearchFile(context.Context, *SearchFileRequest) (*SearchFileResponse, error) // Flows CollectArtifact(context.Context, *proto.ArtifactCollectorArgs) (*proto.ArtifactCollectorResponse, error) CancelFlow(context.Context, *ApiFlowRequest) (*StartFlowResponse, error) @@ -987,6 +1000,9 @@ func (UnimplementedAPIServer) VFSStatDownload(context.Context, *VFSStatDownloadR func (UnimplementedAPIServer) GetTable(context.Context, *GetTableRequest) (*GetTableResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetTable not implemented") } +func (UnimplementedAPIServer) SearchFile(context.Context, *SearchFileRequest) (*SearchFileResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchFile not implemented") +} func (UnimplementedAPIServer) CollectArtifact(context.Context, *proto.ArtifactCollectorArgs) (*proto.ArtifactCollectorResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CollectArtifact not implemented") } @@ -1654,6 +1670,24 @@ func _API_GetTable_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _API_SearchFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SearchFileRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).SearchFile(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.API/SearchFile", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).SearchFile(ctx, req.(*SearchFileRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _API_CollectArtifact_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(proto.ArtifactCollectorArgs) if err := dec(in); err != nil { @@ -2471,6 +2505,10 @@ var API_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetTable", Handler: _API_GetTable_Handler, }, + { + MethodName: "SearchFile", + Handler: _API_SearchFile_Handler, + }, { MethodName: "CollectArtifact", Handler: _API_CollectArtifact_Handler, diff --git a/api/proto/vfs_api.pb.go b/api/proto/vfs_api.pb.go index 7a40fce7fa2..12700537132 100644 --- a/api/proto/vfs_api.pb.go +++ b/api/proto/vfs_api.pb.go @@ -397,6 +397,154 @@ func (x *VFSDownloadFileRequest) GetVfsComponents() []string { return nil } +type SearchFileRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + VfsComponents []string `protobuf:"bytes,2,rep,name=vfs_components,json=vfsComponents,proto3" json:"vfs_components,omitempty"` + // If true pad sparse files. + Padding bool `protobuf:"varint,7,opt,name=padding,proto3" json:"padding,omitempty"` + // The term to search for + Term string `protobuf:"bytes,3,opt,name=term,proto3" json:"term,omitempty"` + // The type of search term - default "string", "regex" + Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` + // Where to begin the search + Offset uint64 `protobuf:"varint,5,opt,name=offset,proto3" json:"offset,omitempty"` + // If true we search forward otherwise we search backwards from + // the offset + Forward bool `protobuf:"varint,6,opt,name=forward,proto3" json:"forward,omitempty"` +} + +func (x *SearchFileRequest) Reset() { + *x = SearchFileRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchFileRequest) ProtoMessage() {} + +func (x *SearchFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchFileRequest.ProtoReflect.Descriptor instead. +func (*SearchFileRequest) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{5} +} + +func (x *SearchFileRequest) GetVfsComponents() []string { + if x != nil { + return x.VfsComponents + } + return nil +} + +func (x *SearchFileRequest) GetPadding() bool { + if x != nil { + return x.Padding + } + return false +} + +func (x *SearchFileRequest) GetTerm() string { + if x != nil { + return x.Term + } + return "" +} + +func (x *SearchFileRequest) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +func (x *SearchFileRequest) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *SearchFileRequest) GetForward() bool { + if x != nil { + return x.Forward + } + return false +} + +type SearchFileResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + VfsComponents []string `protobuf:"bytes,2,rep,name=vfs_components,json=vfsComponents,proto3" json:"vfs_components,omitempty"` + Hit uint64 `protobuf:"varint,3,opt,name=hit,proto3" json:"hit,omitempty"` +} + +func (x *SearchFileResponse) Reset() { + *x = SearchFileResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SearchFileResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SearchFileResponse) ProtoMessage() {} + +func (x *SearchFileResponse) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SearchFileResponse.ProtoReflect.Descriptor instead. +func (*SearchFileResponse) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{6} +} + +func (x *SearchFileResponse) GetVfsComponents() []string { + if x != nil { + return x.VfsComponents + } + return nil +} + +func (x *SearchFileResponse) GetHit() uint64 { + if x != nil { + return x.Hit + } + return 0 +} + var File_vfs_api_proto protoreflect.FileDescriptor var file_vfs_api_proto_rawDesc = []byte{ @@ -454,7 +602,23 @@ var file_vfs_api_proto_rawDesc = []byte{ 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x66, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x76, 0x66, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, - 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x64, + 0x73, 0x22, 0xae, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x66, 0x73, 0x5f, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x0d, 0x76, 0x66, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x12, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x66, 0x6f, 0x72, 0x77, 0x61, + 0x72, 0x64, 0x22, 0x4d, 0x0a, 0x12, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x46, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x66, 0x73, 0x5f, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0d, 0x76, 0x66, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, + 0x10, 0x0a, 0x03, 0x68, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x03, 0x68, 0x69, + 0x74, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, @@ -472,21 +636,23 @@ func file_vfs_api_proto_rawDescGZIP() []byte { return file_vfs_api_proto_rawDescData } -var file_vfs_api_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_vfs_api_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_vfs_api_proto_goTypes = []interface{}{ (*VFSListResponse)(nil), // 0: proto.VFSListResponse (*VFSStatDownloadRequest)(nil), // 1: proto.VFSStatDownloadRequest (*VFSListRequest)(nil), // 2: proto.VFSListRequest (*VFSListRequestState)(nil), // 3: proto.VFSListRequestState (*VFSDownloadFileRequest)(nil), // 4: proto.VFSDownloadFileRequest - (*proto.VQLRequest)(nil), // 5: proto.VQLRequest - (*proto.VQLTypeMap)(nil), // 6: proto.VQLTypeMap - (*proto.VQLResponse)(nil), // 7: proto.VQLResponse + (*SearchFileRequest)(nil), // 5: proto.SearchFileRequest + (*SearchFileResponse)(nil), // 6: proto.SearchFileResponse + (*proto.VQLRequest)(nil), // 7: proto.VQLRequest + (*proto.VQLTypeMap)(nil), // 8: proto.VQLTypeMap + (*proto.VQLResponse)(nil), // 9: proto.VQLResponse } var file_vfs_api_proto_depIdxs = []int32{ - 5, // 0: proto.VFSListResponse.Query:type_name -> proto.VQLRequest - 6, // 1: proto.VFSListResponse.types:type_name -> proto.VQLTypeMap - 7, // 2: proto.VFSListRequestState.current:type_name -> proto.VQLResponse + 7, // 0: proto.VFSListResponse.Query:type_name -> proto.VQLRequest + 8, // 1: proto.VFSListResponse.types:type_name -> proto.VQLTypeMap + 9, // 2: proto.VFSListRequestState.current:type_name -> proto.VQLResponse 3, // [3:3] is the sub-list for method output_type 3, // [3:3] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name @@ -560,6 +726,30 @@ func file_vfs_api_proto_init() { return nil } } + file_vfs_api_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchFileRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vfs_api_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SearchFileResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -567,7 +757,7 @@ func file_vfs_api_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_vfs_api_proto_rawDesc, NumEnums: 0, - NumMessages: 5, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/vfs_api.proto b/api/proto/vfs_api.proto index c7330c1b2df..a885d5be91a 100644 --- a/api/proto/vfs_api.proto +++ b/api/proto/vfs_api.proto @@ -56,3 +56,30 @@ message VFSDownloadFileRequest { repeated string vfs_components = 2; } + + +message SearchFileRequest { + repeated string vfs_components = 2; + + // If true pad sparse files. + bool padding = 7; + + // The term to search for + string term = 3; + + // The type of search term - default "string", "regex" + string type = 4; + + // Where to begin the search + uint64 offset = 5; + + // If true we search forward otherwise we search backwards from + // the offset + bool forward = 6; +} + +message SearchFileResponse { + repeated string vfs_components = 2; + + uint64 hit = 3; +} \ No newline at end of file diff --git a/artifacts/definitions/Server/Monitor/Health.yaml b/artifacts/definitions/Server/Monitor/Health.yaml index 04056c5ad5a..30a8536fc58 100644 --- a/artifacts/definitions/Server/Monitor/Health.yaml +++ b/artifacts/definitions/Server/Monitor/Health.yaml @@ -67,7 +67,7 @@ reports: ## Current Orgs - {{ Query "LET ColumnTypes <= dict(ClientConfig='url') \ + {{ Query "LET ColumnTypes <= dict(ClientConfig='url_internal') \ SELECT Name, OrgId, \ format(format='[%s](/notebooks/Dashboards/%s/uploads/client.%s.config.yaml)', \ args=[OrgId, ArtifactName, OrgId]) AS ClientConfig, \ diff --git a/gui/velociraptor/src/components/artifacts/artifacts.jsx b/gui/velociraptor/src/components/artifacts/artifacts.jsx index bd30bb65d73..1c23ac87b1b 100644 --- a/gui/velociraptor/src/components/artifacts/artifacts.jsx +++ b/gui/velociraptor/src/components/artifacts/artifacts.jsx @@ -27,13 +27,13 @@ import SplitPane from 'react-split-pane'; const presetFilters = [ {value: "type:CLIENT", label: T("Client Artifacts")}, + {value: "type:SERVER", label: T("Server Artifacts")}, {value: "", label: T("All Artifacts")}, {value: "precondition:WINDOWS", label: T("Windows Only")}, {value: "precondition:LINUX", label: T("Linux Only")}, {value: "precondition:DARWIN", label: T("OSX Only")}, {value: "type:CLIENT_EVENT", label: T("Client Monitoring")}, {value: "type:SERVER_EVENT", label: T("Servr Monitoring")}, - {value: "type:SERVER", label: T("Server Artifacts")}, {value: "tool:.+", label: T("Using Tools")}, {value: "^exchange.+", label: T("Exchange")}, {value: "^custom.+", label: T("Custom")}, @@ -89,7 +89,7 @@ class ArtifactInspector extends React.Component { showEditedArtifactDialog: false, showDeleteArtifactDialog: false, showArtifactsUploadDialog: false, - current_filter: "", + current_filter: "type:CLIENT", version: 0, @@ -103,7 +103,7 @@ class ArtifactInspector extends React.Component { this.props.match.params.artifact; if (!artifact_name) { - this.fetchRows("..."); + this.fetchRows("type:CLIENT"); return; } this.setState({selectedDescriptor: {name: artifact_name}, diff --git a/gui/velociraptor/src/components/bootstrap/pagination/PageItem.jsx b/gui/velociraptor/src/components/bootstrap/pagination/PageItem.jsx deleted file mode 100644 index 573ef7cdfe3..00000000000 --- a/gui/velociraptor/src/components/bootstrap/pagination/PageItem.jsx +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react'; -import getStyles from './utils/getStyles'; - -const PageItem = ({ - text, - page, - className, - onClick, - href, - activeBgColor, - activeBorderColor, - disabledBgColor, - disabledBorderColor, - bgColor, - borderColor, - activeColor, - disabledColor, - color, - circle, - shadow, - size -}) => ( -
  • - onClick && onClick(page, e)} - {...onClick ? { href: '#' } : { href: href }} > - {text} - -
  • - ); - -const circleStyle = (isCircle, size) => { - if (!isCircle) return {} - if (size === 'lg' || size === 'sm') { - if (size === 'lg') { - return { - borderRadius: '30px', - marginLeft: '6px', - marginRight: '6px', - width: '57px', - height: '57px', - padding: '.75rem 17px' - } - } - if (size === 'sm') { - return { - borderRadius: '30px', - marginLeft: '4px', - marginRight: '4px', - width: '36px', - height: '36px', - padding: '7px' - } - } - } else { - return { - borderRadius: '30px', - marginLeft: '6px', - marginRight: '6px', - width: '45px', - height: '45px', - padding: '11px' - } - } -} - -const shadowStyle = (showShadow, isCircle) => { - if (!showShadow) return {} - if (!isCircle) return {} - return { - WebkitBoxShadow: '0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)', - boxShadow: '0px 8px 17px 0px rgba(0,0,0,0.2),0px 6px 20px 0px rgba(0,0,0,0.19)' - } -} - -export default PageItem; diff --git a/gui/velociraptor/src/components/bootstrap/pagination/index.jsx b/gui/velociraptor/src/components/bootstrap/pagination/index.jsx deleted file mode 100644 index 99887be1d0e..00000000000 --- a/gui/velociraptor/src/components/bootstrap/pagination/index.jsx +++ /dev/null @@ -1,119 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { getPagination } from './utils/getPagination'; -import PageItem from './PageItem'; - -export default class Pagination extends React.Component { - - render() { - - const { - onClick, - size, - ariaLabel, - activeBgColor, - activeBorderColor, - disabledBgColor, - disabledBorderColor, - bgColor, - borderColor, - activeColor, - color, - disabledColor, - circle, - shadow, - center, - className - } = this.props; - const pagination = getPagination(this.props); - return ( - - - ); - } -} - -Pagination.propTypes = { - totalPages: PropTypes.number.isRequired, - currentPage: PropTypes.number.isRequired, - ariaLabel: PropTypes.string, - size: PropTypes.string, - showMax: PropTypes.number, - activeClass: PropTypes.string, - defaultClass: PropTypes.string, - disabledClass: PropTypes.string, - threeDots: PropTypes.bool, - href: PropTypes.string, - pageOneHref: PropTypes.string, - prevNext: PropTypes.bool, - prevText: PropTypes.string, - nextText: PropTypes.string, - center: PropTypes.bool, - onClick: PropTypes.func, - activeBgColor: PropTypes.string, - activeBorderColor: PropTypes.string, - disabledBgColor: PropTypes.string, - disabledBorderColor: PropTypes.string, - bgColor: PropTypes.string, - borderColor: PropTypes.string, - activeColor: PropTypes.string, - disabledColor: PropTypes.string, - color: PropTypes.string, - circle: PropTypes.bool, - shadow: PropTypes.bool, - className: PropTypes.string -}; - -Pagination.defaultProps = { - currentPage: 1, - ariaLabel: 'Page navigator', - activeClass: 'active', - disabledClass: 'disabled', - showMax: 5, - center: false, - size: 'md', // sm md lg - prevNext: true, - prevText: '⟨', - nextText: '⟩', - circle: false, - shadow: false, -} - -const shadowStyle = (showShadow, isCircle) => { - if (!showShadow) return {} - if (isCircle) return {} - return { - WebkitBoxShadow: '0 8px 17px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)', - boxShadow: '0px 8px 17px 0px rgba(0,0,0,0.2),0px 6px 20px 0px rgba(0,0,0,0.19)' - } -} diff --git a/gui/velociraptor/src/components/bootstrap/pagination/readme.md b/gui/velociraptor/src/components/bootstrap/pagination/readme.md deleted file mode 100644 index 55e827d363b..00000000000 --- a/gui/velociraptor/src/components/bootstrap/pagination/readme.md +++ /dev/null @@ -1,125 +0,0 @@ -[![NPM](https://nodei.co/npm/react-bootstrap-4-pagination.png?downloads=true)](https://nodei.co/npm/react-bootstrap-4-pagination/) - -# react-bootstrap-4-pagination - -**A React component to render and manage Bootstrap 4 pagination quickly and easily.** - -Your project must have [Bootstrap 4](https://getbootstrap.com/docs/4.0/getting-started/introduction/) in order to properly render the component - -Check [Live example](https://codesandbox.io/s/react-bootstrap-4-pagination-12efe) - -## Installation - -Install `react-bootstrap-4-pagination` with [npm](https://www.npmjs.com/): - -``` -$ npm install react-bootstrap-4-pagination -``` - -## Usage - -Very easy to use. Just provide props with total amount of things that you want to display on the page. - -#### With href - -```js -import React from 'react'; -import Pagination from 'react-bootstrap-4-pagination'; - -let paginationConfig = { - totalPages: 22, - currentPage: 15, - showMax: 5, - size: "lg", - threeDots: true, - prevNext: true, - href: 'https://example.com/items?page=*', // * will be replaced by the page number - pageOneHref: 'https://example.com/items', - borderColor: 'red', - activeBorderColor: 'black', - activeBgColor: 'grey', - disabledBgColor: 'red', - activeColor: 'red', - color: 'purple', - disabledColor: 'green', - circle: true, - shadow: true -}; - -function App() { - return ( -
    - -
    - ); -} - -export default App; - -``` - -#### With function - -```js -import React from 'react'; -import Pagination from 'react-bootstrap-4-pagination'; - -let paginationConfig = { - totalPages: 7, - currentPage: 3, - showMax: 5, - size: "lg", - threeDots: true, - prevNext: true, - onClick: function (page) { - console.log(page); - } -}; - -function App() { - return ( -
    - -
    - ); -} - -export default App; - -``` - - - -## Params - -Name | Type | Default | Description ---- | --- | --- | --- | -`totalPages` | Number | | **Required.** Total number of pages. -`currentPage` | Number | `1` | Current page -`showMax` | Number | 5 | Total page items to display excluding navigation blocks (prev, next, first, last pages) -`onClick` | Function | | Page item click handler. Receive pageNumber as arg. If you pass onClick prop, href prop will stop having effect -`size` | String | `md` | Pagination component size. Options: `sm` `lg` -`prevNext` | Boolean | `true` | Set to `false` if you don't want to show next and prev navigation buttons -`prevText` | String | `⟨` | Text of prev page navigation button -`nextText` | String | `⟩` | Text of prev page navigation button -`href` | String | | Href template. Example: `https://example.com/items?page=*&sessionId=Khf3124nfj` * will be replaced by the page item number -`pageOneHref` | String | | Href template for first page. Example: `https://example.com/items?sessionId=Khf3124nfj` if pageOneHref is not set, page one links will have the href template -`threeDots` | Boolean | `false` | Set to `true`if you want to show Ellipsis items -`activeClass` | String | `active` | Class name of active `
  • ` tag -`disabledClass` | String | `disabled` | Class name of the first, previous, next and last `
  • ` tags when disabled -`center` | Boolean | `true` | Set to `false` if you don't whant to center pagination items -`activeBgColor` | String | Bootstrap default | `background-color: ` of active class page items -`activeBorderColor` | String | Bootstrap default | `border-color: ` of active class page items -`activeColor` | String | Bootstrap default | `color: ` (font color) of active class page items -`disabledBgColor` | String | Bootstrap default | `background-color: ` of disabled class page items -`disabledBorderColor` | String | Bootstrap default | `border-color: ` of disabled class page items -`disabeldColor` | String | Bootstrap default | `color: ` (font color) of disabled class page itmes -`bgColor` | String | Bootstrap default | `background-color: ` of page items that don't have active or disabled class -`borderColor` | String | Bootstrap default | `border-color: ` of page items that don't have active or disabled class -`color` | String | Bootstrap default | `color: ` (font color) of page items that don't have active or disabled class -`circle` | Boolean | `false` | Set to true if you want circular page items -`shadow` | Boolean | `false` | Set to true if you want shadow on page items -`ariaLabel` | String | `Page navigator` | `aria-label` text of nav element - -## License -[MIT](https://choosealicense.com/licenses/mit/) diff --git a/gui/velociraptor/src/components/bootstrap/pagination/utils/getPagination.jsx b/gui/velociraptor/src/components/bootstrap/pagination/utils/getPagination.jsx deleted file mode 100644 index c0082706851..00000000000 --- a/gui/velociraptor/src/components/bootstrap/pagination/utils/getPagination.jsx +++ /dev/null @@ -1,73 +0,0 @@ -const getPagination = (props) => { - - let arr = []; - let startAt = props.currentPage - Math.floor(props.showMax / 2); - let isPositive = () => Math.sign(startAt); - if (isPositive() === -1 || isPositive() === 0) startAt = 1; - let max = startAt + props.showMax; - if (max > props.totalPages) { - max = props.totalPages; - } - - for (let i = startAt; i < max; i++) { - arr.push({ - page: i, - text: i, - isCurrent: isCurrent(i, props.currentPage), - class: isCurrent(i, props.currentPage) ? props.activeClass : props.defaultClass, - href: i === 1 ? props.href && props.pageOneHref : props.href && props.href.replace('*', startAt + i) - }); - } - - if (props.threeDots) { - if (arr.length) { - arr = addThreeDots(arr, props); - } - } - - if (props.prevNext) { - if (arr.length) { - arr = addNext(arr, props); - arr = addPrev(arr, props); - } - } - - return arr; -} - -const isCurrent = (page, currentPage) => currentPage === page; - -const addThreeDots = (arr, props) => { - let threeDotsObj = { page: false, text: '...', isCurrent: false, class: props.disabledClass }; - arr[0].page !== 1 && arr.unshift(threeDotsObj) && arr.unshift({ page: 1, text: 1, isCurrent: false, class: props.defaultClass, href: props.pageOneHref ? props.pageOneHref : props.href && props.href.replace('*', 1) }); - arr[arr.length - 1].page !== props.totalPages && arr.push(threeDotsObj) && arr.push({ page: props.totalPages, text: props.totalPages, isCurrent: false, class: props.defaultClass, href: props.href && props.href.replace('*', props.totalPages) }); - return arr; -} - -const addNext = (arr, props) => { - let nextObj = { - page: props.currentPage + 1, - text: props.nextText, - isCurrent: false, - class: props.currentPage + 1 > props.totalPages && props.disabledClass, - href: props.href && props.href.replace('*', props.currentPage + 1) - }; - arr.push(nextObj); - return arr; -} - -const addPrev = (arr, props) => { - let prevObj = { - page: props.currentPage - 1, - text: props.prevText, - isCurrent: false, - class: props.currentPage - 1 < 1 && props.disabledClass, - href: props.href && props.href.replace('*', props.currentPage - 1) - }; - arr.unshift(prevObj); - return arr; -} - -export { - getPagination -} diff --git a/gui/velociraptor/src/components/bootstrap/pagination/utils/getStyles.jsx b/gui/velociraptor/src/components/bootstrap/pagination/utils/getStyles.jsx deleted file mode 100644 index ed5c6c67a84..00000000000 --- a/gui/velociraptor/src/components/bootstrap/pagination/utils/getStyles.jsx +++ /dev/null @@ -1,26 +0,0 @@ -const getStyles = (styles, className) => { - switch (className) { - case undefined || false: - return { - color: styles.color && styles.color, - backgroundColor: styles.bgColor, - borderColor: styles.borderColor - } - case 'disabled': - return { - color: styles.disabledColor && styles.disabledColor, - backgroundColor: styles.disabledBgColor ? styles.disabledBgColor : styles.bgColor, - borderColor: styles.disabledBorderColor ? styles.disabledBorderColor : styles.borderColor - } - case 'active': - return { - color: styles.activeColor && styles.activeColor, - backgroundColor: styles.activeBgColor, - borderColor: styles.activeBorderColor - } - default: - break; - } -} - -export default getStyles; \ No newline at end of file diff --git a/gui/velociraptor/src/components/core/api-service.jsx b/gui/velociraptor/src/components/core/api-service.jsx index 96946a5ae39..44c7734e8e2 100644 --- a/gui/velociraptor/src/components/core/api-service.jsx +++ b/gui/velociraptor/src/components/core/api-service.jsx @@ -234,7 +234,10 @@ const upload = function(url, files, params) { // Prepare a suitable href link for const href = function(url, params, options) { params = params || {}; - Object.assign(params, {org_id: window.globals.OrgId || "root"}); + // Relative URLs are always internal. + if(url.startsWith("/") || (options && options.internal)) { + Object.assign(params, {org_id: window.globals.OrgId || "root"}); + } options = options || {}; Object.assign(options, {indices: false}); @@ -268,7 +271,12 @@ const src_of = function (url) { return url; } return window.base_path + url; -} +}; + + +const error = function(msg) { + _.each(hooks, h=>h(msg)); +}; /* eslint import/no-anonymous-default-export: [2, {"allowObject": true}] */ export default { @@ -279,6 +287,7 @@ export default { hooks: hooks, base_path: base_path, href: href, + error: error, delete_req: delete_req, src_of: src_of, }; diff --git a/gui/velociraptor/src/components/core/paged-table.jsx b/gui/velociraptor/src/components/core/paged-table.jsx index 65588b1f837..98b10328127 100644 --- a/gui/velociraptor/src/components/core/paged-table.jsx +++ b/gui/velociraptor/src/components/core/paged-table.jsx @@ -36,7 +36,6 @@ import { } from './table.jsx'; - const pageListRenderer = ({ pages, currentPage, @@ -55,7 +54,9 @@ const pageListRenderer = ({ } return ( - onPageChange(0)}/> + onPageChange(0)}/> { pageWithoutIndication.map((p, idx)=>( )) } - onPageChange(totalPages)}/> + onPageChange(totalPages)}/> + }), {internal: true})}> {T("Download JSON")} @@ -611,7 +616,7 @@ class VeloPagedTable extends Component { Object.assign(downloads, { timezone: timezone, download_format: "csv", - }))}> + }), {internal: true})}> {T("Download CSV")} diff --git a/gui/velociraptor/src/components/core/table.jsx b/gui/velociraptor/src/components/core/table.jsx index d60690d0f61..1ada55f24c8 100644 --- a/gui/velociraptor/src/components/core/table.jsx +++ b/gui/velociraptor/src/components/core/table.jsx @@ -518,6 +518,18 @@ export function formatColumns(columns, env, column_formatter) { x.type = null; break; + case "url_internal": + x.formatter = (cell, row) => { + if(_.isObject(cell)) { + return ; + } + return ; + }; + x.type = null; + break; + + case "safe_url": x.formatter = (cell, row) => { return ; diff --git a/gui/velociraptor/src/components/events/timeline-viewer.jsx b/gui/velociraptor/src/components/events/timeline-viewer.jsx index aa39f8c0383..029e2a711f7 100644 --- a/gui/velociraptor/src/components/events/timeline-viewer.jsx +++ b/gui/velociraptor/src/components/events/timeline-viewer.jsx @@ -374,7 +374,8 @@ export default class EventTimelineViewer extends React.Component { @@ -385,7 +386,8 @@ export default class EventTimelineViewer extends React.Component { diff --git a/gui/velociraptor/src/components/flows/flow-uploads.jsx b/gui/velociraptor/src/components/flows/flow-uploads.jsx index 82a26cf8ed2..b90aba25b2b 100644 --- a/gui/velociraptor/src/components/flows/flow-uploads.jsx +++ b/gui/velociraptor/src/components/flows/flow-uploads.jsx @@ -78,7 +78,9 @@ export default class FlowUploads extends React.Component { row._Components, this.props.flow.client_id, this.props.flow.session_id), padding: true, - vfs_path: filename}, {arrayFormat: 'brackets'})}> + vfs_path: filename}, { + internal: true, + arrayFormat: 'brackets'})}> {filename}    @@ -101,7 +103,9 @@ export default class FlowUploads extends React.Component { row._Components, this.props.flow.client_id, this.props.flow.session_id), padding: false, - vfs_path: filename}, {arrayFormat: 'brackets'})}> + vfs_path: filename}, { + internal: true, + arrayFormat: 'brackets'})}> {filename} ; diff --git a/gui/velociraptor/src/components/notebooks/downloads.jsx b/gui/velociraptor/src/components/notebooks/downloads.jsx index 5fdd970063a..a64ad2fec65 100644 --- a/gui/velociraptor/src/components/notebooks/downloads.jsx +++ b/gui/velociraptor/src/components/notebooks/downloads.jsx @@ -21,7 +21,8 @@ export default class AvailableDownloads extends Component { return {row.name}; } return <> diff --git a/gui/velociraptor/src/components/notebooks/export-notebook.jsx b/gui/velociraptor/src/components/notebooks/export-notebook.jsx index 4e8e2546d18..cbe235daae2 100644 --- a/gui/velociraptor/src/components/notebooks/export-notebook.jsx +++ b/gui/velociraptor/src/components/notebooks/export-notebook.jsx @@ -70,7 +70,8 @@ export default class ExportNotebook extends React.Component { return {row.name}; }; return <> diff --git a/gui/velociraptor/src/components/users/user-inspector.jsx b/gui/velociraptor/src/components/users/user-inspector.jsx index d49f983f2f3..c95f5dad426 100644 --- a/gui/velociraptor/src/components/users/user-inspector.jsx +++ b/gui/velociraptor/src/components/users/user-inspector.jsx @@ -80,6 +80,8 @@ class ConfirmDialog extends Component { class PermissionViewer extends Component { static propTypes = { + username: PropTypes.string, + org: PropTypes.object, acls: PropTypes.object, setACL: PropTypes.func.isRequired, } @@ -134,12 +136,25 @@ class PermissionViewer extends Component { } render() { - if (_.size(this.props.acls) === 0) { - return <>; + if (!this.props.username) { + return <>; } - let org_name = this.props.acls.org_name || "root"; + if (_.isEmpty(this.props.org)) { + return
    + + {T("Please Select an Org")} +
    ; + } + if (_.isEmpty(this.props.acls)) { + return
    + {T("Loading ACLs")} +
    ; + } + + let org_name = this.props.acls.org_name || "root"; return ( - {T("Update User Password")} + + {T("Update User Password")} + } @@ -440,7 +459,9 @@ class UsersOverview extends Component { variant="outline-default" as="button"> - {T("Assign user to Orgs")} + + {T("Assign user to Orgs")} + @@ -448,6 +469,8 @@ class UsersOverview extends Component { { _.isEmpty(selected_orgs) && + {T("Please Select a User")} } @@ -470,6 +493,8 @@ class UsersOverview extends Component { @@ -559,6 +584,8 @@ class OrgsOverview extends UsersOverview { diff --git a/gui/velociraptor/src/components/users/user-label.jsx b/gui/velociraptor/src/components/users/user-label.jsx index 88cc7c6fa7f..32c7c950d20 100644 --- a/gui/velociraptor/src/components/users/user-label.jsx +++ b/gui/velociraptor/src/components/users/user-label.jsx @@ -454,6 +454,11 @@ export default class UserLabel extends React.Component { } { this.orgName() } + ); diff --git a/gui/velociraptor/src/components/utils/context.css b/gui/velociraptor/src/components/utils/context.css index dc6280daa78..42c79180c70 100644 --- a/gui/velociraptor/src/components/utils/context.css +++ b/gui/velociraptor/src/components/utils/context.css @@ -12,3 +12,7 @@ div.react-contexify { div.react-contexify .react-contexify__item__content { color: var(--color-foreground); } + +.context-menu-available { + cursor: context-menu; +} diff --git a/gui/velociraptor/src/components/utils/context.jsx b/gui/velociraptor/src/components/utils/context.jsx index 76a7194a178..44153bb10e3 100644 --- a/gui/velociraptor/src/components/utils/context.jsx +++ b/gui/velociraptor/src/components/utils/context.jsx @@ -36,11 +36,11 @@ export default function ContextMenu({children, value}) { }); return ( -
    -
    +
    {children}
    -
    ); } diff --git a/gui/velociraptor/src/components/utils/csv.jsx b/gui/velociraptor/src/components/utils/csv.jsx index b96999151df..7caadb65431 100644 --- a/gui/velociraptor/src/components/utils/csv.jsx +++ b/gui/velociraptor/src/components/utils/csv.jsx @@ -22,7 +22,7 @@ export function parseCSV(data) { } } catch(e) { - _.each(api.hooks, h=>h("Error: " + e)); + api.error("Error: " + e); return {columns: ["Column1"], data: []}; } diff --git a/gui/velociraptor/src/components/utils/hex.css b/gui/velociraptor/src/components/utils/hex.css index e95a256fc53..b184b7e1a5c 100644 --- a/gui/velociraptor/src/components/utils/hex.css +++ b/gui/velociraptor/src/components/utils/hex.css @@ -36,6 +36,38 @@ th.offset { margin-left: 30px; } -td.hex-container { +td.context-container { display: inline-block; + width: 20em; +} + +.hex-padding { + padding-left: 1.2em; + display: inline-block; + height: 1em; +} + +.hex-char { + padding-right: 1em; + height: 1em; + display: inline-block; +} + +.text-char { + display: inline-block; + height: 1em; +} + +.hex-highlight { + background: var(--hex-highlight-background); + color: var(--hex-highlight-foreground); + height: 100%; +} + +.hex-viewer { + overflow-x: auto; +} + +.hex-viewer table { + max-width: 100%; } diff --git a/gui/velociraptor/src/components/utils/hex.jsx b/gui/velociraptor/src/components/utils/hex.jsx index 368226a5916..38d792afb29 100644 --- a/gui/velociraptor/src/components/utils/hex.jsx +++ b/gui/velociraptor/src/components/utils/hex.jsx @@ -6,6 +6,9 @@ import _ from 'lodash'; import Button from 'react-bootstrap/Button'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import Modal from 'react-bootstrap/Modal'; +import T from '../i8n/i8n.jsx'; +import { UnstyledBaseHexEditor } from 'react-hex-editor'; +import Form from 'react-bootstrap/Form'; export class HexViewDialog extends React.PureComponent { static propTypes = { @@ -96,19 +99,27 @@ export class HexViewPopup extends React.Component { // A hex viewer suitable for small amountfs of text - No paging. export default class HexView extends React.Component { static propTypes = { + highlights: PropTypes.object, + // Version of the highlights array to manage highligh updates + highlight_version: PropTypes.number, + base_offset: PropTypes.number, byte_array: PropTypes.any, + // Version of the byte_array to manage updates of the data. + version: PropTypes.any, data: PropTypes.string, height: PropTypes.number, max_height: PropTypes.number, + setColumns: PropTypes.func, columns: PropTypes.number, }; state = { hexDataRows: [], rows: 25, - columns: 0x10, page: 0, expanded: false, + hex_offset: false, + highlights: {}, } componentDidMount = () => { @@ -117,7 +128,11 @@ export default class HexView extends React.Component { componentDidUpdate = (prevProps, prevState, rootNode) => { if (!_.isEqual(prevProps.data, this.props.data) || - !_.isEqual(prevProps.byte_array, this.props.byte_array)) { + !_.isEqual(prevProps.version, this.props.version) || + !_.isEqual(prevProps.highlight_version, this.props.highlight_version) || + !_.isEqual(prevProps.base_offset, this.props.base_offset) || + !_.isEqual(prevProps.byte_array, this.props.byte_array) || + !_.isEqual(prevProps.highlights, this.props.highlights)) { this.updateRepresentation(); } } @@ -126,104 +141,103 @@ export default class HexView extends React.Component { if (this.props.byte_array) { this.parseintArrayToHexRepresentation_(this.props.byte_array); } else { - this.parseFileContentToHexRepresentation_(this.props.data); + let utf8_encode = new TextEncoder().encode(this.props.data); + this.parseintArrayToHexRepresentation_(utf8_encode); } } + shouldHighlight = (offset)=>{ + if(_.isUndefined(this.props.highlights)) { + return false; + }; + + // highlights is a map of key->name and value->a list of specs. + for(const highlight of Object.values(this.props.highlights)) { + for(const spec of highlight) { + if (offset >= spec.start && offset < spec.end) { + return true; + } + } + } + return false; + } + + // Populate the hex viewer from the byte_array prop parseintArrayToHexRepresentation_ = (intArray) => { if (!intArray) { intArray = ""; } let hexDataRows = []; - var chunkSize = this.state.rows * this.state.columns; + let columns = this.props.columns || 16; + var chunkSize = this.state.rows * columns; + let base_offset = this.props.base_offset || 0; + let offset = this.state.page * chunkSize; for(var i = 0; i < this.state.rows; i++){ - let offset = this.state.page * chunkSize; - var rowOffset = offset + (i * this.state.columns); - var data = intArray.slice(i * this.state.columns, (i+1)*this.state.columns); + var rowOffset = offset + (i * columns); + var data = intArray.slice(i * columns, (i+1)*columns); var data_row = []; - var safe_data = ""; for (var j = 0; j < data.length; j++) { - var char = data[j].toString(16); + let char = data[j].toString(16); + // add leading zero if necessary + let text = ('0' + char).substr(-2); + + // Add a printable char for the text. + let safe = "."; if (data[j] > 0x20 && data[j] < 0x7f) { - safe_data += String.fromCharCode(data[j]); + safe = String.fromCharCode(data[j]); + }; + + if (this.shouldHighlight(base_offset + rowOffset + j)) { + data_row.push({v: text, h: true, safe: safe}); } else { - safe_data += "."; + data_row.push({v: text, safe: safe}); }; - data_row.push(('0' + char).substr(-2)); // add leading zero if necessary }; // Pad with extra spaces to maintain alignment - let pad = this.state.rows - data.length % this.state.columns; - for (var j = 0; j < pad; j++) { - safe_data += " "; - data_row.push(" "); + if(data_row.length < columns) { + let pad = columns - data_row.length % columns; + for (var j = 0; j < pad; j++) { + data_row.push({v:" ", p:true, safe:" "}); + } } hexDataRows.push({ - offset: rowOffset, + offset: base_offset + rowOffset, data_row: data_row, data: data, - safe_data: safe_data, }); } this.setState({hexDataRows: hexDataRows, loading: false}); }; - parseFileContentToHexRepresentation_ = (fileContent) => { - if (!fileContent) { - fileContent = ""; - } - - // The absolute maximum height we will render. - let max_height = this.props.max_height || 1000; - let columns = this.props.columns || 16; - let hexDataRows = []; - for(var i = 0; i < max_height; i++){ - let offset = 0; - var rowOffset = offset + (i * columns); - var data = fileContent.substr(i * columns, columns); - var data_row = []; - for (var j = 0; j < data.length; j++) { - var char = data.charCodeAt(j).toString(16); - data_row.push(('0' + char).substr(-2)); // add leading zero if necessary - }; - - if (data_row.length === 0) { - break; - }; - - let safe_data = data.replace(/[^\x20-\x7f]/g, '.'); - safe_data = safe_data.split(" "); - hexDataRows.push({ - offset: rowOffset, - data_row: data_row, - data: data, - safe_data: safe_data, - }); - - } - - this.setState({hexDataRows: hexDataRows, loading: false}); - }; - - render() { let height = this.props.height || 5; + let columns = this.props.columns || 16; let more = this.state.hexDataRows.length > height; let hexArea = { _.map(this.state.hexDataRows, (row, idx)=>{ if (idx >= height && !this.state.expanded) { - return <>; + return ; } - return + return ; }) @@ -236,12 +250,19 @@ export default class HexView extends React.Component { { _.map(this.state.hexDataRows, (row, idx)=>{ if (idx >= height && !this.state.expanded) { - return <>; + return ; } return ; @@ -251,17 +272,46 @@ export default class HexView extends React.Component { return (
    -
    +
    { _.map(row.data_row, (x, idx)=>{ - return { x } ; + let cname = "hex-char"; + if(x.h) { + cname += " hex-highlight"; + } else if(x.p) { + cname = "hex-padding"; + } + return + { x.v } + ; })}
    - { _.map(row.safe_data, (x, idx)=>{ - return { x } ; + { _.map(row.data_row, (x, idx)=>{ + let cname = "text-char"; + if(x.h) { + cname += " hex-highlight"; + } + return + { x.safe } + ; })}
    + - @@ -271,11 +321,15 @@ export default class HexView extends React.Component { { _.map(this.state.hexDataRows, (row, idx)=>{ if (idx >= height && !this.state.expanded) { - return <>; + return
    ; + } + let offset = row.offset; + if (this.state.hex_offset) { + offset = "0x" + offset.toString(16); } - return + return ; })} @@ -284,7 +338,7 @@ export default class HexView extends React.Component { - @@ -292,7 +346,7 @@ export default class HexView extends React.Component { : - - ) } + + ) }
    - Offset + - 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + {_.map(_.range(0, columns), (x, idx)=>{ + let x_str = x.toString(16); + x_str = ('0' + x_str).substr(-2); + return {x_str}; + })} + + { this.props.setColumns && + { + this.props.setColumns( + parseInt(e.target.value)); + }} + > + + + + }
    - { row.offset } + { offset }
    { hexArea } + { contextArea }
    - -
    + +
    diff --git a/gui/velociraptor/src/components/utils/url.jsx b/gui/velociraptor/src/components/utils/url.jsx index a35b48df727..52c9277a9ce 100644 --- a/gui/velociraptor/src/components/utils/url.jsx +++ b/gui/velociraptor/src/components/utils/url.jsx @@ -18,6 +18,10 @@ export default class URLViewer extends Component { url: PropTypes.string, desc: PropTypes.string, safe: PropTypes.bool, + + // If specified this is an intenral link - so we add org id + // etc. + internal: PropTypes.bool, } state = { @@ -43,7 +47,9 @@ export default class URLViewer extends Component { className="url-link" size="sm" variant="outline-info" - href={api.href(url)} target="_blank"> + href={api.href(url, { + internal: this.props.internal, + })} target="_blank"> {desc} ; diff --git a/gui/velociraptor/src/components/vfs/browse-vfs.jsx b/gui/velociraptor/src/components/vfs/browse-vfs.jsx index 75aa0c7b0f4..9496a30a8a9 100644 --- a/gui/velociraptor/src/components/vfs/browse-vfs.jsx +++ b/gui/velociraptor/src/components/vfs/browse-vfs.jsx @@ -7,7 +7,7 @@ import SplitPane from 'react-split-pane'; import VeloFileTree from './file-tree.jsx'; import VeloFileList from './file-list.jsx'; -import VeloFileDetails from './file-details.jsx'; +import VeloFileStats from './file-stats.jsx'; class VFSViewer extends Component { @@ -68,9 +68,8 @@ class VFSViewer extends Component { updateCurrentSelectedRow={this.updateCurrentSelectedRow} version={this.props.node && this.props.node.version} node={this.state.current_node} /> - diff --git a/gui/velociraptor/src/components/vfs/file-details.jsx b/gui/velociraptor/src/components/vfs/file-details.jsx index 4a86f9ecdcf..95ea6304e48 100644 --- a/gui/velociraptor/src/components/vfs/file-details.jsx +++ b/gui/velociraptor/src/components/vfs/file-details.jsx @@ -5,12 +5,8 @@ import PropTypes from 'prop-types'; import T from '../i8n/i8n.jsx'; import VeloFileStats from './file-stats.jsx'; -import FileHexView from './file-hex-view.jsx'; -import FileTextView from './file-text-view.jsx'; -import Tabs from 'react-bootstrap/Tabs'; -import Tab from 'react-bootstrap/Tab'; -export default class VeloFileDetails extends React.Component { +export default class VeloFileDetails extends React.PureComponent { static propTypes = { client: PropTypes.object, @@ -23,47 +19,18 @@ export default class VeloFileDetails extends React.Component { updateCurrentNode: PropTypes.func, }; - state = { - tab: "stats", - } - render() { let selectedRow = this.props.selectedRow; - let has_download = selectedRow && selectedRow.Download && selectedRow.Download.mtime; + let has_download = selectedRow && + selectedRow.Download && selectedRow.Download.mtime; return ( -
    - this.setState({tab: tab})}> - - - - - { this.state.tab === "text" && - } - - - { this.state.tab === "hex" && - } - - -
    + ); } } diff --git a/gui/velociraptor/src/components/vfs/file-hex-view.css b/gui/velociraptor/src/components/vfs/file-hex-view.css deleted file mode 100644 index 641d74fa8f7..00000000000 --- a/gui/velociraptor/src/components/vfs/file-hex-view.css +++ /dev/null @@ -1,40 +0,0 @@ - -.file-hex-view .pagination { - margin: 5px 0; -} - -.file-hex-view nav { - margin: 20px; -} - -.file-hex-view table .offset { - font-weight: bold; - color: var(--color-table-row-offset); - padding-right: 20px; - padding-left: 20px; -} - -.file-hex-view table td { - vertical-align: top !important; -} - -.file-hex-view table .data { - padding-left: 2ex; - white-space: nowrap; -} - -.file-hex-view .no-content { - text-align: center; - margin-top: 50px; - font-size: 2.0em; - color: var(--color-no-content-color); -} - - -.file-hex-view td, .file-hex-view th { - border: 0px; -} - -.file-hex-view td, .file-hex-view button { - width: fit-content; -} diff --git a/gui/velociraptor/src/components/vfs/file-hex-view.jsx b/gui/velociraptor/src/components/vfs/file-hex-view.jsx deleted file mode 100644 index b3d983353fc..00000000000 --- a/gui/velociraptor/src/components/vfs/file-hex-view.jsx +++ /dev/null @@ -1,213 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import _ from 'lodash'; -import api from '../core/api-service.jsx'; -import Pagination from '../bootstrap/pagination/index.jsx'; -import Spinner from '../utils/spinner.jsx'; -import axios from 'axios'; -import "./file-hex-view.css"; -import T from '../i8n/i8n.jsx'; - -export default class FileHexView extends React.Component { - static propTypes = { - node: PropTypes.object, - selectedRow: PropTypes.object, - client: PropTypes.object, - }; - - state = { - page: 0, - rows: 25, - columns: 0x10, - hexDataRows: [], - loading: true, - } - - componentDidMount = () => { - this.source = axios.CancelToken.source(); - this.fetchText_(0); - } - - componentWillUnmount() { - this.source.cancel("unmounted"); - } - - componentDidUpdate = (prevProps, prevState, rootNode) => { - // Update the view when - // 1. Selected node changes (file list was selected). - // 2. VFS path changes (tree navigated away). - // 3. node version changes (file was refreshed). - if (!_.isEqual(prevProps.selectedRow, this.props.selectedRow) || - !_.isEqual(prevProps.node.path, this.props.node.path) || - prevProps.node.version !== this.props.node.version) { - this.fetchText_(this.state.page); - }; - } - - fetchText_ = (page) => { - let selectedRow = this.props.selectedRow; - let client_id = this.props.client && this.props.client.client_id; - if (!client_id) { - return; - } - - let name = selectedRow && selectedRow.Name; - if (!name) { - return; - } - - let vfs_components = selectedRow.Download && selectedRow.Download.components; - if (!vfs_components) { - return; - } - - var chunkSize = this.state.rows * this.state.columns; - var url = 'v1/DownloadVFSFile'; - - // vfsFileDownloadRequest struct schema in /api/download.go - var params = { - offset: page * chunkSize, - length: chunkSize, - fs_components: vfs_components, - client_id: client_id, - }; - - this.setState({loading: true}); - api.get_blob(url, params, this.source.token).then(buffer=> { - const view = new Uint8Array(buffer); - this.parseFileContentToHexRepresentation_(view, page); - }); - }; - - parseFileContentToHexRepresentation_ = (intArray, page) => { - if (!intArray) { - intArray = ""; - } - let hexDataRows = []; - var chunkSize = this.state.rows * this.state.columns; - - for(var i = 0; i < this.state.rows; i++){ - let offset = page * chunkSize; - var rowOffset = offset + (i * this.state.columns); - var data = intArray.slice(i * this.state.columns, (i+1)*this.state.columns); - var data_row = []; - var safe_data = ""; - for (var j = 0; j < data.length; j++) { - var char = data[j].toString(16); - if (data[j] > 0x20 && data[j] < 0x7f) { - safe_data += String.fromCharCode(data[j]); - } else { - safe_data += "."; - }; - data_row.push(('0' + char).substr(-2)); // add leading zero if necessary - }; - - hexDataRows.push({ - offset: rowOffset, - data_row: data_row, - data: data, - safe_data: safe_data, - }); - } - - this.setState({hexDataRows: hexDataRows, loading: false}); - }; - - - render() { - let selectedRow = this.props.selectedRow; - let mtime = selectedRow && selectedRow.Download && selectedRow.Download.mtime; - if (!mtime) { - return
    {T("File has no data, please collect file first.")}
    ; - } - - var total_size = selectedRow.Size || 0; - var chunkSize = this.state.rows * this.state.columns; - let pageCount = Math.ceil(total_size / chunkSize); - let paginationConfig = { - totalPages: pageCount, - currentPage: this.state.page + 1, - showMax: 5, - size: "sm", - threeDots: true, - center: true, - prevNext: true, - shadow: true, - onClick: (page, e) => { - this.setState({page: page - 1}); - this.fetchText_(page - 1); - e.preventDefault(); - e.stopPropagation(); - }, - }; - - let hexArea = this.state.loading ? T("Loading") : - - - { _.map(this.state.hexDataRows, function(row, idx) { - return - - ; }) - } - -
    - { _.map(row.data_row, function(x, idx) { - return { x } ; - })} -
    ; - - let contextArea = this.state.loading ? "" : - - - { _.map(this.state.hexDataRows, function(row, idx) { - return ; - })} - -
    { row.safe_data }
    ; - - return ( -
    - -
    - { pageCount && } - -
    -
    - - - - - - - - - - - - - - - -
    {T("Offset")}00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
    - - - { _.map(this.state.hexDataRows, function(row, idx) { - return - - ; })} - -
    - 0x{ row.offset.toString(16) } -
    -
    - { hexArea } - - { contextArea } -
    -
    -
    -
    -
    - ); - } -}; diff --git a/gui/velociraptor/src/components/vfs/file-stats.jsx b/gui/velociraptor/src/components/vfs/file-stats.jsx index 119888864d3..8f9b2e7812b 100644 --- a/gui/velociraptor/src/components/vfs/file-stats.jsx +++ b/gui/velociraptor/src/components/vfs/file-stats.jsx @@ -12,6 +12,7 @@ import api from '../core/api-service.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import axios from 'axios'; import T from '../i8n/i8n.jsx'; +import PreviewUpload from '../widgets/preview_uploads.jsx'; const POLL_TIME = 2000; @@ -185,7 +186,9 @@ class VeloFileStats extends Component { client_id: client_id, fs_components: selectedRow.Download.components, vfs_path: selectedRow.Name, - }, {arrayFormat: 'brackets'})}> + }, { + internal: true, + arrayFormat: 'brackets'})}> @@ -246,6 +249,19 @@ class VeloFileStats extends Component {
    MD5
    {selectedRow.Download.MD5}
    } + { !_.isEmpty(selectedRow.Download.components) && +
    +
    {T("Preview")}
    +
    + +
    +
    } diff --git a/gui/velociraptor/src/components/vfs/file-text-view.jsx b/gui/velociraptor/src/components/vfs/file-text-view.jsx deleted file mode 100644 index cb0ad7b1bdf..00000000000 --- a/gui/velociraptor/src/components/vfs/file-text-view.jsx +++ /dev/null @@ -1,146 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import _ from 'lodash'; -import api from '../core/api-service.jsx'; -import Pagination from '../bootstrap/pagination/index.jsx'; -import Spinner from '../utils/spinner.jsx'; -import VeloAce from '../core/ace.jsx'; -import axios from 'axios'; -import "./file-hex-view.css"; -import T from '../i8n/i8n.jsx'; - -const pagesize = 100 * 1024; - -export default class FileTextView extends React.Component { - static propTypes = { - selectedRow: PropTypes.object, - node: PropTypes.object, - client: PropTypes.object, - }; - - state = { - page: 0, - rawdata: "", - loading: false, - } - - componentDidMount = () => { - this.source = axios.CancelToken.source(); - this.fetchText_(0); - } - - componentWillUnmount() { - this.source.cancel("unmounted"); - } - - componentDidUpdate = (prevProps, prevState, rootNode) => { - // Update the view when - // 1. Selected node changes (file list was selected). - // 2. VFS path changes (tree navigated away). - // 3. node version changes (file was refreshed). - // 4. page is changed - if (!_.isEqual(prevProps.selectedRow, this.props.selectedRow) || - !_.isEqual(prevProps.node.path, this.props.node.path) || - prevProps.node.version !== this.props.node.version || - prevState.page !== this.state.page) { - this.fetchText_(this.state.page); - }; - } - - fetchText_ = (page) => { - let selectedRow = this.props.selectedRow; - let client_id = this.props.client && this.props.client.client_id; - if (!client_id) { - return; - } - - let name = selectedRow && selectedRow.Name; - if (!name) { - return; - } - - let vfs_components = selectedRow.Download && selectedRow.Download.components; - if (!vfs_components) { - return; - } - - var url = 'v1/DownloadVFSFile'; - var params = { - offset: page * pagesize, - length: pagesize, - fs_components: vfs_components, - client_id: client_id, - }; - - this.setState({loading: true}); - api.get_blob(url, params, this.source.token).then(buffer=>{ - const view = new Uint8Array(buffer); - this.parseFileContentToTextRepresentation_(view, page); - }, ()=>{ - this.setState({hexDataRows: [], loading: false, page: page}); - }); - }; - - parseFileContentToTextRepresentation_ = (intArray, page) => { - let rawdata = ""; - let line_length = 0; - for (var i = 0; i < intArray.length; i++) { - if(intArray[i] > 0x20 && intArray[i]<0x7f) { - rawdata += String.fromCharCode(intArray[i]); - } else { - rawdata += "."; - } - line_length += 1; - if (intArray[i] === 0xa) { - line_length = 0; - rawdata += "\n"; - } - if (line_length > 80) { - rawdata += "\n"; - line_length = 0; - } - }; - this.setState({rawdata: rawdata, loading: false, page: page}); - }; - - - render() { - let selectedRow = this.props.selectedRow; - let mtime = selectedRow && selectedRow.Download && selectedRow.Download.mtime; - if (!mtime) { - return
    {T("File has no data, please collect file first.")}
    ; - } - var total_size = selectedRow.Size || 0; - let pageCount = Math.ceil(total_size / pagesize); - let paginationConfig = { - totalPages: pageCount, - currentPage: this.state.page + 1, - showMax: 5, - size: "sm", - threeDots: true, - center: true, - prevNext: true, - shadow: true, - onClick: (page, e) => { - this.setState({page: page - 1}); - e.preventDefault(); - e.stopPropagation(); - }, - }; - - return ( -
    - -
    - - -
    -
    - ); - } -}; diff --git a/gui/velociraptor/src/components/widgets/pagination.jsx b/gui/velociraptor/src/components/widgets/pagination.jsx new file mode 100644 index 00000000000..3d637d8f9ee --- /dev/null +++ b/gui/velociraptor/src/components/widgets/pagination.jsx @@ -0,0 +1,111 @@ +import _ from 'lodash'; + +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Pagination from 'react-bootstrap/Pagination'; +import Form from 'react-bootstrap/Form'; +import T from '../i8n/i8n.jsx'; +import classNames from "classnames"; + + +export default class HexPaginationControl extends React.Component { + static propTypes = { + total_pages: PropTypes.number, + page_size: PropTypes.number, + total_size: PropTypes.number, + current_page: PropTypes.number, + onPageChange: PropTypes.func, + showGoToPage: PropTypes.bool, + hex_offset: PropTypes.bool, + set_highlights: PropTypes.func, + } + + state = { + goto_offset: "", + goto_error: false, + } + + gotoPage = page=>{ + let new_offset = page*this.props.page_size; + if (this.props.hex_offset) { + new_offset = "0x" + new_offset.toString(16); + } + this.setState({goto_offset: new_offset}); + this.clearHighlight(); + this.props.onPageChange(page); + } + + clearHighlight = ()=>{ + if(this.props.set_highlights) { + this.props.set_highlights("offset", []); + } + } + + setHighlight = offset=>{ + if(this.props.set_highlights) { + this.props.set_highlights("offset", [{ + start: offset, + end: offset+4}]); + } + } + + render() { + let last_page = this.props.total_pages-1; + if (last_page <= 0) { + last_page = 0; + } + return ( + + this.gotoPage(0)}/> + this.gotoPage(this.props.current_page-1)}/> + + { + let goto_offset = e.target.value; + this.setState({goto_offset: goto_offset}); + + if (goto_offset === "") { + return; + } + + let base_offset = parseInt(goto_offset); + if (isNaN(base_offset)) { + this.setState({goto_error: true}); + return; + } + this.setState({goto_error: false}); + + if (base_offset > this.props.total_size) { + goto_offset = this.props.total_size; + base_offset = this.props.total_size; + this.setState({ + goto_offset: goto_offset, + }); + } + this.setHighlight(base_offset); + + let page = parseInt(base_offset/this.props.page_size); + this.props.onPageChange(page); + }}/> + this.gotoPage(this.props.current_page+1)}/> + this.gotoPage(last_page)}/> + + ); + } +} diff --git a/gui/velociraptor/src/components/widgets/preview_uploads.css b/gui/velociraptor/src/components/widgets/preview_uploads.css index 89d0609697e..994d45b3aba 100644 --- a/gui/velociraptor/src/components/widgets/preview_uploads.css +++ b/gui/velociraptor/src/components/widgets/preview_uploads.css @@ -1,3 +1,9 @@ +.file-hex-view { + margin-left: 0px; + margin-right: 0px; + max-width: 3000px; + width: 100%; +} img.preview-thumbnail { max-width: 140px; @@ -16,3 +22,25 @@ img.preview-thumbnail { .textdump { overflow-wrap: break-word; } + +.hex-goto { + margin-top: 26px; + margin-left: 0px; + margin-right: 0px; +} + +.hexview-search-type-selector { + max-width: 7em; +} + +input.goto-invalid.form-control, +input.goto-invalid.form-control:focus { + background-color: #f8d7da; + background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); + background-repeat: repeat-x; + border-color: #dca7a7; +} + +.preview-json { + margin-top: 45px; +} diff --git a/gui/velociraptor/src/components/widgets/preview_uploads.jsx b/gui/velociraptor/src/components/widgets/preview_uploads.jsx index 97a723d3ba9..41e5946a22e 100644 --- a/gui/velociraptor/src/components/widgets/preview_uploads.jsx +++ b/gui/velociraptor/src/components/widgets/preview_uploads.jsx @@ -9,9 +9,11 @@ import api from '../core/api-service.jsx'; import Button from 'react-bootstrap/Button'; import qs from 'qs'; import Modal from 'react-bootstrap/Modal'; +import Container from 'react-bootstrap/Container'; import HexView from '../utils/hex.jsx'; +import SearchHex from './search.jsx'; import Spinner from '../utils/spinner.jsx'; -import Pagination from '../bootstrap/pagination/index.jsx'; +import HexPaginationControl from './pagination.jsx'; import Tab from 'react-bootstrap/Tab'; import Tabs from 'react-bootstrap/Tabs'; import T from '../i8n/i8n.jsx'; @@ -19,6 +21,9 @@ import VeloValueRenderer from '../utils/value.jsx'; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import Form from 'react-bootstrap/Form'; +import Nav from 'react-bootstrap/Nav'; +import InputGroup from 'react-bootstrap/InputGroup'; // https://en.wikipedia.org/wiki/List_of_file_signatures const patterns = [ @@ -64,7 +69,7 @@ class HexViewTab extends React.PureComponent { componentDidMount = () => { this.source = axios.CancelToken.source(); - this.fetchPage_(); + this.fetchPage_(0); } componentWillUnmount() { @@ -73,21 +78,27 @@ class HexViewTab extends React.PureComponent { componentDidUpdate = (prevProps, prevState, rootNode) => { if (!_.isEqual(prevProps.params, this.props.params) || - !_.isEqual(prevState.page, this.state.page)) { - this.fetchPage_(); + !_.isEqual(prevState.page, this.state.page) || + !_.isEqual(prevState.columns, this.state.columns)) { + this.fetchPage_(this.state.page); }; } state = { + // The offset in the file where this screen views + base_offset: 0, page: 0, rows: 25, columns: 0x10, view: undefined, loading: true, textview_only: false, + highlights: {}, + highlight_version: 0, + version: 0, } - fetchPage_ = () => { + fetchPage_ = (page, ondone) => { let params = Object.assign({}, this.props.params); this.source.cancel(); @@ -96,14 +107,17 @@ class HexViewTab extends React.PureComponent { // read a bit more than we need to so the text view looks a // bit more full. params.length = this.state.rows * this.state.columns * 2; - params.offset = this.state.page * this.state.rows * this.state.columns; + params.offset = page * this.state.rows * this.state.columns; api.get_blob(this.props.url, params, this.source.token).then(buffer=>{ const view = new Uint8Array(buffer); this.setState({ + base_offset: params.offset, view: view, + version: this.state.version+1, rawdata: this.parseFileContentToTextRepresentation_(view), loading: false}); + if(ondone) {ondone();}; }); this.setState({loading: true}); } @@ -127,74 +141,103 @@ class HexViewTab extends React.PureComponent { return rawdata; }; - render() { var chunkSize = this.state.rows * this.state.columns; let total_size = this.props.size || 0; let pageCount = Math.ceil(total_size / chunkSize); - let paginationConfig = { - totalPages: pageCount, - currentPage: this.state.page + 1, - showMax: 5, - size: "sm", - threeDots: true, - center: true, - prevNext: true, - shadow: true, - onClick: (page, e) => { - this.setState({page: page - 1}); - this.fetchPage_(page - 1); - e.preventDefault(); - e.stopPropagation(); - }, - }; return ( -
    + - { } + + + + + + { + let h = this.state.highlights; + h[name] = hits; + this.setState({ + highlights: h, + highlight_version: this.state.highlight_version+1}); + }} + onPageChange={page=>{ + this.fetchPage_(page, ()=>{ + this.setState({ + base_offset: page * chunkSize, + page: page, + }); + }); + }} + /> + + + { + this.fetchPage_(page, ()=>{ + this.setState({ + base_offset: page * chunkSize, + page: page, + }); + }); + }} + set_highlights={(name, hits)=>{ + let h = this.state.highlights; + h[name] = hits; + this.setState({ + highlights: h, + highlight_version: this.state.highlight_version+1}); + }}/> + + { this.state.textview_only ? -
    {this.state.rawdata}
    : <> - +
    this.setState({columns: v})} columns={this.state.columns} - byte_array={this.state.view} /> -
    - - - -
    -
    {this.state.rawdata}
    + // The data that will be rendered + byte_array={this.state.view} + version={this.state.version} />
    }
    -
    +
    ); } } @@ -235,7 +278,9 @@ class InspectDialog extends React.PureComponent { { this.state.tab === "details" && - } +
    + +
    }
    @@ -285,7 +330,7 @@ export default class PreviewUpload extends Component { if(env.hunt_id) return true; if(env.notebook_cell_id) return true; if(env.client_id && env.flow_id) return true; - + if(env.client_id && env.vfs_components) return true; return false; } diff --git a/gui/velociraptor/src/components/widgets/search.css b/gui/velociraptor/src/components/widgets/search.css new file mode 100644 index 00000000000..9d6af5d0300 --- /dev/null +++ b/gui/velociraptor/src/components/widgets/search.css @@ -0,0 +1,12 @@ +.search-term-error { + position: absolute; + display: block; + top: -2em; + left: 2em; + z-index: 100; + color: var(--color-level-error); +} + +.hexview-search-input { + max-width: 20em; +} diff --git a/gui/velociraptor/src/components/widgets/search.jsx b/gui/velociraptor/src/components/widgets/search.jsx new file mode 100644 index 00000000000..03940cf3782 --- /dev/null +++ b/gui/velociraptor/src/components/widgets/search.jsx @@ -0,0 +1,219 @@ +import "./search.css"; + +import _ from 'lodash'; +import axios from 'axios'; + +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import Pagination from 'react-bootstrap/Pagination'; +import Button from 'react-bootstrap/Button'; +import Form from 'react-bootstrap/Form'; +import T from '../i8n/i8n.jsx'; + +import api from '../core/api-service.jsx'; + + +export default class SearchHex extends React.Component { + static propTypes = { + base_offset: PropTypes.number, + vfs_components: PropTypes.array, + current_page: PropTypes.number, + page_size: PropTypes.number, + onPageChange: PropTypes.func, + set_highlights: PropTypes.func, + byte_array: PropTypes.any, + version: PropTypes.any, + } + + state = { + search_type: "regex", + search_term: "", + search_term_error: "", + loading: false, + } + + componentDidMount = () => { + this.source = axios.CancelToken.source(); + } + + componentWillUnmount() { + this.source.cancel(); + } + + componentDidUpdate = (prevProps, prevState, rootNode) => { + if (!_.isEqual(prevProps.version, this.props.version) || + !_.isEqual(prevState.search_term, this.state.search_term)) { + this.updateHighlights(this.state.search_term, + this.state.search_type); + }; + } + + processHit = response=>{ + if (response.cancel) return; + + if(_.isEmpty(response.data.vfs_components) || !response.data) { + api.error("Error: No match found"); + return; + } + + let hit_page = parseInt(response.data.hit / + this.props.page_size); + this.props.onPageChange(hit_page); + this.setState({loading: false}); + } + + searchNext = ()=>{ + // Cancel any in flight calls. + this.source.cancel(); + this.source = axios.CancelToken.source(); + + if (!this.props.vfs_components) { + return; + } + + this.setState({loading: true}); + api.post("v1/SearchFile", { + term: this.state.search_term, + type: this.state.search_type, + vfs_components: this.props.vfs_components, + + // Start searching from the next page + offset: this.props.base_offset + this.props.page_size, + forward: true, + }, this.source.token).then(this.processHit); + } + + searchPrev = ()=>{ + // Cancel any in flight calls. + this.source.cancel(); + this.source = axios.CancelToken.source(); + + if (!this.props.vfs_components) { + return; + } + + this.setState({loading: true}); + api.post("v1/SearchFile", { + term: this.state.search_term, + type: this.state.search_type, + vfs_components: this.props.vfs_components, + + // Start searching from the next page + offset: this.props.base_offset, + forward: false, + }, this.source.token).then(this.processHit); + } + + updateHighlights = (search_term, search_type)=>{ + if (!search_term) { + return; + } + + if (search_type === "string") { + this.updateHighlightsForString(search_term); + + } else if (search_type === "regex") { + this.updateHighlightsForRegex(search_term); + + } else if(search_type ==="hex") { + search_term = search_term.replaceAll(" ", ""); + let decoded = ""; + for (let i = 0; i < search_term.length; i += 2) { + let char = search_term.substr(i, 2); + if(char.match(/[0-9a-f]{2}/i)) { + decoded += String.fromCharCode(parseInt(char, 16)); + } else { + this.setState({search_term_error: "Invalid hex string"}); + this.props.set_highlights("search", []); + return; + } + } + + if (decoded) { + this.setState({search_term_error: ""}); + this.updateHighlightsForString(decoded); + } + } + } + + updateHighlightsForString = search_term=>{ + let hits = []; + let utf8_buffer = new TextDecoder().decode(this.props.byte_array); + let term_length = search_term.length; + let start = -1; + for(;;) { + let idx = utf8_buffer.indexOf(search_term, start+1); + if (idx<0) { + break; + } + hits.push({start: idx + this.props.base_offset, + end: idx+ this.props.base_offset + + search_term.length}); + start = idx+1; + } + this.props.set_highlights("search", hits); + return; + } + + updateHighlightsForRegex = search_term=>{ + let hits = []; + let utf8_buffer = new TextDecoder('latin1').decode(this.props.byte_array); + let re = undefined; + try { + re = new RegExp(search_term, "gi"); + this.setState({search_term_error: ""}); + + } catch(e) { + this.setState({search_term_error: e.message}); + this.props.set_highlights("search", []); + return; + }; + + for(;;) { + let m = re.exec(utf8_buffer); + if (!m) { + break; + } + hits.push({start: m.index + this.props.base_offset, + end: m.index + m[0].length + this.props.base_offset}); + } + this.props.set_highlights("search", hits); + return; + } + + render() { + return + { this.state.search_term_error && +
    + {T(this.state.search_term_error)} +
    } + this.searchPrev()}/> + { + this.setState({search_type: e.target.value}); + this.updateHighlights( + this.state.search_term, e.target.value); + }} + value={this.state.search_type}> + + + + + { + this.setState({search_term: e.target.value}); + }} + placeholder={T("Search for string or hex")} + /> + this.searchNext()}/> +
    ; + } +} diff --git a/gui/velociraptor/src/css/_variables.css b/gui/velociraptor/src/css/_variables.css index 85b963926a2..5a5e4c65700 100644 --- a/gui/velociraptor/src/css/_variables.css +++ b/gui/velociraptor/src/css/_variables.css @@ -85,4 +85,7 @@ --color-accent-75: #0096ffb0; --color-accent-50: #0096ff80; --color-accent-25: #0096ff40; + + --hex-highlight-background: var(--color-foreground); + --hex-highlight-foreground: var(--color-canvas-background); } diff --git a/gui/velociraptor/src/index.jsx b/gui/velociraptor/src/index.jsx index 515d4f80d14..ea7b941aeba 100644 --- a/gui/velociraptor/src/index.jsx +++ b/gui/velociraptor/src/index.jsx @@ -23,7 +23,7 @@ import { faHome, faCrosshairs, faWrench, faEye, faServer, faBook, faLaptop, faFileCode, faFlag, faTrashAlt, faClock, faLock, faLockOpen, faCloud, faCloudDownloadAlt, faUserEdit, faFilter, faSortAlphaUp, faSortAlphaDown, faInfo, faBug, faUser, faList, faIndent, faTextHeight, faBars, - faUserLargeSlash, faTriangleExclamation, faCircle, + faUserLargeSlash, faTriangleExclamation, faCircle, faAnglesLeft, } from '@fortawesome/free-solid-svg-icons'; library.add(faHome, faCrosshairs, faWrench, faEye, faServer, faBook, faLaptop, @@ -39,7 +39,8 @@ library.add(faHome, faCrosshairs, faWrench, faEye, faServer, faBook, faLaptop, faBookmark, faHeart, faFileCode, faFlag, faTrashAlt, faClock, faLock, faLockOpen, faCloud, faCloudDownloadAlt, faUserEdit, faFilter, faBug, faSortAlphaUp, faSortAlphaDown, faInfo, faUser, faList, faIndent, - faTextHeight, faBars, faUserLargeSlash, faTriangleExclamation, faCircle, + faTextHeight, faBars, faUserLargeSlash, faTriangleExclamation, + faCircle, faAnglesLeft, ); ReactDOM.render( diff --git a/gui/velociraptor/src/themes/veloci-light.css b/gui/velociraptor/src/themes/veloci-light.css index 57c4f3477dc..21958bb758d 100644 --- a/gui/velociraptor/src/themes/veloci-light.css +++ b/gui/velociraptor/src/themes/veloci-light.css @@ -122,6 +122,9 @@ --color-vfs-files-timestomped: #ed5d40; --color-level-error: #990000; + + --hex-highlight-background: var(--accent-color); + --hex-highlight-foreground: var(--color-canvas-background); } body.veloci-light { diff --git a/vql/functions/unhex.go b/vql/functions/unhex.go index 380519a475e..2fd55437b39 100644 --- a/vql/functions/unhex.go +++ b/vql/functions/unhex.go @@ -27,7 +27,9 @@ func (self *UnhexFunction) Call(ctx context.Context, return false } - res, _ := hex.DecodeString(strings.TrimPrefix(arg.String, "0x")) + // Strip all spaces + str := strings.Replace(arg.String, " ", "", -1) + res, _ := hex.DecodeString(strings.TrimPrefix(str, "0x")) return string(res) }