From 3c0b3f131676fc5eeaa99f16e0e41fd9b585ba38 Mon Sep 17 00:00:00 2001 From: Mike Cohen Date: Tue, 25 Apr 2023 14:44:30 +1000 Subject: [PATCH] Improved eslint score (#2642) Also added DELETE_RESULTS permissions to allow finer control over who can delete results. --- acls/acls.go | 7 ++ acls/proto/acl.pb.go | 40 ++++++---- acls/proto/acl.proto | 1 + acls/roles.go | 8 ++ api/filesearch.go | 2 +- api/proto/api.pb.gw.go | 28 +++---- .../testdata/server/testcases/orgs.out.yaml | 15 ++-- .../testdata/server/testcases/users.out.yaml | 6 +- go.mod | 2 +- go.sum | 4 +- gui/velociraptor/.eslintrc.cjs | 10 ++- gui/velociraptor/package.json | 22 ++--- gui/velociraptor/src/App.jsx | 9 ++- gui/velociraptor/src/App.test.jsx | 9 --- .../components/artifacts/artifacts-upload.jsx | 4 +- .../src/components/artifacts/artifacts.css | 19 +++++ .../src/components/artifacts/artifacts.jsx | 35 +++++--- .../src/components/artifacts/line-charts.jsx | 1 + .../src/components/artifacts/new-artifact.jsx | 4 +- .../src/components/artifacts/reporting.jsx | 13 ++- .../src/components/clients/client-link.jsx | 3 + .../src/components/clients/client-status.jsx | 1 - .../src/components/clients/client-summary.jsx | 6 +- .../src/components/clients/client_info.jsx | 7 +- .../src/components/clients/clients-list.jsx | 14 ++-- .../src/components/clients/host-info.jsx | 14 ++-- .../src/components/clients/metadata.jsx | 17 +--- .../src/components/clients/search.jsx | 10 ++- .../src/components/clients/shell-viewer.jsx | 16 ++-- .../src/components/core/ace-config.jsx | 2 - gui/velociraptor/src/components/core/ace.jsx | 7 +- .../src/components/core/api-service.jsx | 4 +- .../src/components/core/keyboard-help.jsx | 80 ++++++++++--------- .../src/components/core/paged-table.jsx | 8 +- .../src/components/core/table.jsx | 6 ++ gui/velociraptor/src/components/core/user.jsx | 9 ++- .../src/components/events/delete.jsx | 1 + .../src/components/events/event-notebook.jsx | 4 +- .../src/components/events/event-table.jsx | 15 ++-- .../src/components/events/events.jsx | 24 +++--- .../src/components/events/timeline-viewer.jsx | 12 +-- .../components/flows/client-flows-view.jsx | 10 ++- .../components/flows/flow-full-notebook.jsx | 8 +- .../src/components/flows/flow-link.jsx | 4 +- .../src/components/flows/flow-notebook.jsx | 6 +- .../src/components/flows/flow-overview.jsx | 4 +- .../src/components/flows/flow-requests.jsx | 4 +- .../src/components/flows/flow-uploads.jsx | 8 -- .../components/flows/flows-add-to-hunt.jsx | 4 +- .../src/components/flows/flows-inspector.jsx | 10 ++- .../src/components/flows/flows-list.jsx | 37 +++++---- .../src/components/flows/new-collection.jsx | 17 +++- .../components/flows/offline-collector.jsx | 1 + .../components/flows/server-flows-view.jsx | 10 ++- .../src/components/forms/form.jsx | 12 +-- .../src/components/hunts/estimate.jsx | 4 +- .../components/hunts/hunt-full-notebook.jsx | 8 +- .../src/components/hunts/hunt-inspector.jsx | 4 + .../src/components/hunts/hunt-list.jsx | 13 ++- .../src/components/hunts/hunt-notebook.jsx | 4 +- .../src/components/hunts/hunt-overview.jsx | 4 +- .../src/components/hunts/hunts.jsx | 18 +++-- .../src/components/hunts/new-hunt.jsx | 4 +- gui/velociraptor/src/components/i8n/en.jsx | 5 +- .../notebooks/add-cell-from-flow.jsx | 4 +- .../notebooks/create-artifact-from-cell.jsx | 4 +- .../components/notebooks/export-notebook.jsx | 4 +- .../components/notebooks/full_notebook.jsx | 14 +++- .../notebooks/notebook-cell-renderer.jsx | 21 +++-- .../notebooks/notebook-chart-renderer.jsx | 6 +- .../components/notebooks/notebook-delete.jsx | 4 +- .../notebooks/notebook-renderer.jsx | 4 +- .../components/notebooks/notebook-uploads.jsx | 4 +- .../src/components/notebooks/notebook.jsx | 13 ++- .../components/notebooks/notebooks-list.jsx | 21 ++--- .../src/components/notebooks/timelines.jsx | 4 +- .../src/components/server/server-info.jsx | 18 ++--- .../src/components/sidebar/hotkeys.jsx | 3 + .../src/components/sidebar/navigator.jsx | 14 ++-- .../src/components/sidebar/user-dashboard.jsx | 4 +- .../src/components/timeline/timeline.jsx | 8 +- .../src/components/tools/tool-viewer.jsx | 6 +- .../src/components/users/add_orgs.jsx | 6 +- .../src/components/users/add_user.jsx | 8 +- .../src/components/users/edit-user.jsx | 4 +- .../src/components/users/user-inspector.jsx | 18 +++-- .../src/components/users/user-label.jsx | 9 ++- gui/velociraptor/src/components/utils/hex.css | 9 +++ gui/velociraptor/src/components/utils/hex.jsx | 7 +- .../src/components/utils/labels.jsx | 4 +- .../src/components/utils/users.jsx | 4 +- .../src/components/vfs/file-details.css | 26 ------ .../src/components/vfs/file-details.jsx | 36 --------- .../src/components/vfs/file-list.jsx | 13 ++- .../src/components/vfs/file-stats.css | 27 +++++++ .../src/components/vfs/file-stats.jsx | 10 +-- .../src/components/vfs/file-tree.jsx | 10 ++- .../src/components/vfs/vfs-setter.jsx | 3 + .../src/components/welcome/login.jsx | 1 - .../src/components/widgets/pagination.jsx | 4 +- .../components/widgets/preview_uploads.jsx | 13 ++- .../src/components/widgets/search.jsx | 14 ++-- gui/velociraptor/src/css/App.css | 2 +- gui/velociraptor/src/css/_variables.css | 2 +- gui/velociraptor/src/themes/coolgray-dark.css | 2 +- services/acl_manager.go | 4 +- vql/parsers/xml.go | 2 +- vql/server/clients/delete.go | 2 +- vql/server/flows/delete.go | 4 +- vql/server/flows/uploads.go | 9 ++- vql/server/monitoring/delete.go | 4 +- 111 files changed, 630 insertions(+), 481 deletions(-) delete mode 100644 gui/velociraptor/src/App.test.jsx delete mode 100644 gui/velociraptor/src/components/vfs/file-details.css delete mode 100644 gui/velociraptor/src/components/vfs/file-details.jsx diff --git a/acls/acls.go b/acls/acls.go index a93eca80e62..68b92512d55 100644 --- a/acls/acls.go +++ b/acls/acls.go @@ -114,6 +114,9 @@ const ( // Allowed to create zip files. PREPARE_RESULTS + // Allowed to delete results from the server + DELETE_RESULTS + // Allowed raw datastore access DATASTORE_ACCESS @@ -171,6 +174,8 @@ func (self ACL_PERMISSION) String() string { return "MACHINE_STATE" case PREPARE_RESULTS: return "PREPARE_RESULTS" + case DELETE_RESULTS: + return "DELETE_RESULTS" case DATASTORE_ACCESS: return "DATASTORE_ACCESS" @@ -221,6 +226,8 @@ func GetPermission(name string) ACL_PERMISSION { return MACHINE_STATE case "PREPARE_RESULTS": return PREPARE_RESULTS + case "DELETE_RESULTS": + return DELETE_RESULTS case "DATASTORE_ACCESS": return DATASTORE_ACCESS diff --git a/acls/proto/acl.pb.go b/acls/proto/acl.pb.go index 585b7b8b746..1be40872b4c 100644 --- a/acls/proto/acl.pb.go +++ b/acls/proto/acl.pb.go @@ -48,6 +48,7 @@ type ApiClientACL struct { FilesystemWrite bool `protobuf:"varint,14,opt,name=filesystem_write,json=filesystemWrite,proto3" json:"filesystem_write,omitempty"` MachineState bool `protobuf:"varint,16,opt,name=machine_state,json=machineState,proto3" json:"machine_state,omitempty"` PrepareResults bool `protobuf:"varint,17,opt,name=prepare_results,json=prepareResults,proto3" json:"prepare_results,omitempty"` + DeleteResults bool `protobuf:"varint,23,opt,name=delete_results,json=deleteResults,proto3" json:"delete_results,omitempty"` DatastoreAccess bool `protobuf:"varint,18,opt,name=datastore_access,json=datastoreAccess,proto3" json:"datastore_access,omitempty"` // A list of roles in lieu of the permissions above. These will be // interpolated into this ACL object. @@ -226,6 +227,13 @@ func (x *ApiClientACL) GetPrepareResults() bool { return false } +func (x *ApiClientACL) GetDeleteResults() bool { + if x != nil { + return x.DeleteResults + } + return false +} + func (x *ApiClientACL) GetDatastoreAccess() bool { if x != nil { return x.DatastoreAccess @@ -302,7 +310,7 @@ var File_acl_proto protoreflect.FileDescriptor var file_acl_proto_rawDesc = []byte{ 0x0a, 0x09, 0x61, 0x63, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x73, 0x65, 0x6d, 0x61, 0x6e, 0x74, - 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x8f, 0x07, 0x0a, 0x0c, 0x41, 0x70, 0x69, + 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb6, 0x07, 0x0a, 0x0c, 0x41, 0x70, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x43, 0x4c, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x75, 0x70, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x70, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x4b, 0x0a, 0x09, 0x61, 0x6c, 0x6c, 0x5f, @@ -355,20 +363,22 @@ var file_acl_proto_rawDesc = []byte{ 0x28, 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x72, 0x65, 0x70, 0x61, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x70, 0x72, 0x65, 0x70, 0x61, - 0x72, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x61, 0x74, - 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x51, 0x0a, 0x04, 0x52, 0x6f, - 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x43, 0x4c, - 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x32, 0x5a, - 0x30, 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, 0x63, 0x6c, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x72, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, + 0x12, 0x29, 0x0a, 0x10, 0x64, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x61, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x64, 0x61, 0x74, 0x61, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x72, + 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, + 0x73, 0x22, 0x51, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, + 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x41, 0x43, 0x4c, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x32, 0x5a, 0x30, 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, 0x63, + 0x6c, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/acls/proto/acl.proto b/acls/proto/acl.proto index 6d840771fff..7c93b70878f 100644 --- a/acls/proto/acl.proto +++ b/acls/proto/acl.proto @@ -45,6 +45,7 @@ message ApiClientACL { bool filesystem_write = 14; bool machine_state = 16; bool prepare_results = 17; + bool delete_results = 23; bool datastore_access = 18; // A list of roles in lieu of the permissions above. These will be diff --git a/acls/roles.go b/acls/roles.go index e054d334c2a..bda69895796 100644 --- a/acls/roles.go +++ b/acls/roles.go @@ -33,6 +33,7 @@ var ( "FILESYSTEM_WRITE", "MACHINE_STATE", "PREPARE_RESULTS", + "DELETE_RESULTS", "DATASTORE_ACCESS", } ) @@ -101,6 +102,10 @@ func DescribePermissions(token *acl_proto.ApiClientACL) []string { result = append(result, "PREPARE_RESULTS") } + if token.DeleteResults { + result = append(result, "DELETE_RESULTS") + } + if token.DatastoreAccess { result = append(result, "DATASTORE_ACCESS") } @@ -148,6 +153,8 @@ func SetTokenPermission( token.MachineState = true case "PREPARE_RESULTS": token.PrepareResults = true + case "DELETE_RESULTS": + token.DeleteResults = true case "DATASTORE_ACCESS": token.DatastoreAccess = true @@ -188,6 +195,7 @@ func GetRolePermissions( result.FilesystemWrite = true result.MachineState = true result.PrepareResults = true + result.DeleteResults = true // An administrator for the root org is allowed to // manipulate orgs. diff --git a/api/filesearch.go b/api/filesearch.go index 53b8837862a..e28c75c3b4c 100644 --- a/api/filesearch.go +++ b/api/filesearch.go @@ -200,7 +200,7 @@ func newMatcher(term, search_type string) (matcher, error) { return &literal_matcher{[]byte(term)}, nil case "regex": - re, err := regexp.Compile("(?i)" + term) + re, err := regexp.Compile("(?ism)" + term) if err != nil { return nil, err } diff --git a/api/proto/api.pb.gw.go b/api/proto/api.pb.gw.go index 168f9e3646a..73ede2d133a 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_1 "www.velocidex.com/golang/velociraptor/artifacts/proto" - proto_2 "www.velocidex.com/golang/velociraptor/flows/proto" + proto_4 "www.velocidex.com/golang/velociraptor/artifacts/proto" + proto_1 "www.velocidex.com/golang/velociraptor/flows/proto" ) // Suppress "imported and not used" errors @@ -1313,7 +1313,7 @@ func local_request_API_SearchFile_0(ctx context.Context, marshaler runtime.Marsh } 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_2.ArtifactCollectorArgs + var protoReq proto_1.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1330,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_2.ArtifactCollectorArgs + var protoReq proto_1.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1647,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_1.Tool + var protoReq proto_4.Tool var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1663,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_1.Tool + var protoReq proto_4.Tool var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1679,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_1.Tool + var protoReq proto_4.Tool var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1696,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_1.Tool + var protoReq proto_4.Tool var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1765,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_2.ArtifactCollectorArgs + var protoReq proto_1.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1782,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_2.ArtifactCollectorArgs + var protoReq proto_1.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1803,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_2.GetClientMonitoringStateRequest + var protoReq proto_1.GetClientMonitoringStateRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1819,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_2.GetClientMonitoringStateRequest + var protoReq proto_1.GetClientMonitoringStateRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1835,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_2.ClientEventTable + var protoReq proto_1.ClientEventTable var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1852,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_2.ClientEventTable + var protoReq proto_1.ClientEventTable var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) diff --git a/artifacts/testdata/server/testcases/orgs.out.yaml b/artifacts/testdata/server/testcases/orgs.out.yaml index 313031a2428..0264f39596c 100644 --- a/artifacts/testdata/server/testcases/orgs.out.yaml +++ b/artifacts/testdata/server/testcases/orgs.out.yaml @@ -55,7 +55,8 @@ SELECT Name, OrgId FROM orgs() ORDER BY OrgId[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } }, { @@ -89,7 +90,8 @@ SELECT Name, OrgId FROM orgs() ORDER BY OrgId[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } }, { @@ -161,7 +163,8 @@ SELECT Name, OrgId FROM orgs() ORDER BY OrgId[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } }, { @@ -214,7 +217,8 @@ SELECT Name, OrgId FROM orgs() ORDER BY OrgId[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } }, { @@ -284,7 +288,8 @@ SELECT Name, OrgId FROM orgs() ORDER BY OrgId[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } }, { diff --git a/artifacts/testdata/server/testcases/users.out.yaml b/artifacts/testdata/server/testcases/users.out.yaml index 9008e5b525d..0a85c860c5e 100644 --- a/artifacts/testdata/server/testcases/users.out.yaml +++ b/artifacts/testdata/server/testcases/users.out.yaml @@ -110,7 +110,8 @@ SELECT whoami() FROM scope()[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } } ]SELECT user_delete(user="TestUser", really_do_it=TRUE) FROM scope()[ @@ -149,7 +150,8 @@ SELECT whoami() FROM scope()[ "filesystem_read": true, "filesystem_write": true, "machine_state": true, - "prepare_results": true + "prepare_results": true, + "delete_results": true } } ]SELECT user_delete(user="TestUser", really_do_it=TRUE, orgs="ORGID2") FROM scope()[ diff --git a/go.mod b/go.mod index 9ad226c9c99..3a54154a613 100644 --- a/go.mod +++ b/go.mod @@ -102,7 +102,7 @@ require ( www.velocidex.com/golang/go-prefetch v0.0.0-20220801101854-338dbe61982a www.velocidex.com/golang/oleparse v0.0.0-20230217092320-383a0121aafe www.velocidex.com/golang/regparser v0.0.0-20221020153526-bbc758cbd18b - www.velocidex.com/golang/vfilter v0.0.0-20230413031155-cadd50f14c5d + www.velocidex.com/golang/vfilter v0.0.0-20230425012353-b6d0a982ca34 ) require ( diff --git a/go.sum b/go.sum index 196e9258e8b..8a5191e0e5b 100644 --- a/go.sum +++ b/go.sum @@ -1265,7 +1265,7 @@ www.velocidex.com/golang/oleparse v0.0.0-20230217092320-383a0121aafe/go.mod h1:R www.velocidex.com/golang/regparser v0.0.0-20221020153526-bbc758cbd18b h1:NrnjFXwjUi7vdLEDKgSxu6cs304UJLZE/H7pSXXakVA= www.velocidex.com/golang/regparser v0.0.0-20221020153526-bbc758cbd18b/go.mod h1:pxSECT5mWM3goJ4sxB4HCJNKnKqiAlpyT8XnvBwkLGU= www.velocidex.com/golang/vfilter v0.0.0-20220103082604-85bb38175cb7/go.mod h1:eEFMhAmoFHWGCKF39j+iOhTH8REpqBndc3OsdPsxqo8= -www.velocidex.com/golang/vfilter v0.0.0-20230413031155-cadd50f14c5d h1:4CIkMbS48+qG/Dhaziskfxlb6FyQ8PxL3KpquQQuNnM= -www.velocidex.com/golang/vfilter v0.0.0-20230413031155-cadd50f14c5d/go.mod h1:4mDQuvnVu6oPvDu/rZm8eYXh0h8mM7j9CJpj1nRfu8g= +www.velocidex.com/golang/vfilter v0.0.0-20230425012353-b6d0a982ca34 h1:Ww5wvoiNEzTzsGffZsCkc2uIwk1hAJJdNZcLHU7Ogsg= +www.velocidex.com/golang/vfilter v0.0.0-20230425012353-b6d0a982ca34/go.mod h1:4mDQuvnVu6oPvDu/rZm8eYXh0h8mM7j9CJpj1nRfu8g= www.velocidex.com/golang/vtypes v0.0.0-20220816192452-6a27ae078f12 h1:8azOLd/l6sPy1/ug03ueA7jLfsVwE1sI3oHg9q/nkqQ= www.velocidex.com/golang/vtypes v0.0.0-20220816192452-6a27ae078f12/go.mod h1:gpuRaiyhcuPmZYvI/zw+rjlDXklR2ORaLQBuzCXe84o= diff --git a/gui/velociraptor/.eslintrc.cjs b/gui/velociraptor/.eslintrc.cjs index 80f5379908e..4477a4f7f89 100644 --- a/gui/velociraptor/.eslintrc.cjs +++ b/gui/velociraptor/.eslintrc.cjs @@ -1,5 +1,9 @@ module.exports = { - env: { browser: true, node: true }, + env: { + browser: true, + node: true, + es6: true, + }, parser: "@babel/eslint-parser", parserOptions: { requireConfigFile: false, @@ -31,5 +35,9 @@ module.exports = { rules: { // allows characters like <'`&^" "react/no-unescaped-entities": 0, + "no-extra-semi": 0, + "react/display-name": 0, + "no-empty": 0, + "no-unused-vars": ["error", { "args": "none" }], }, }; diff --git a/gui/velociraptor/package.json b/gui/velociraptor/package.json index 98f05f3a7f3..385a490a983 100644 --- a/gui/velociraptor/package.json +++ b/gui/velociraptor/package.json @@ -69,7 +69,7 @@ "scripts": { "build": "vite build", "start": "vite serve", - "lint": "eslint . --ext .js,.jsx", + "lint": "eslint ./src --ext .js,.jsx", "test": "echo \"Error: no test specified\" && exit 1" }, "watch": { @@ -96,15 +96,15 @@ ] }, "devDependencies": { - "@babel/eslint-parser": "^7.19.1", - "@babel/preset-react": "^7.18.6", - "@testing-library/react": "12", - "@vitejs/plugin-react": "^3.0.0", - "eslint": "^8.35.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-react": "^7.32.2", - "vite": "^4.0.1", - "vite-plugin-compression": "^0.5.1" + "@babel/eslint-parser": "^7.19.1", + "@babel/preset-react": "^7.18.6", + "@testing-library/react": "12", + "@vitejs/plugin-react": "^3.0.0", + "eslint": "^8.35.0", + "eslint-plugin-import": "^2.27.5", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.32.2", + "vite": "^4.0.1", + "vite-plugin-compression": "^0.5.1" } } diff --git a/gui/velociraptor/src/App.jsx b/gui/velociraptor/src/App.jsx index f1b0fd9c5a8..66c29672e13 100644 --- a/gui/velociraptor/src/App.jsx +++ b/gui/velociraptor/src/App.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import './css/App.css'; +import PropTypes from 'prop-types'; import VeloNavigator from './components/sidebar/navigator.jsx'; import VeloClientSearch from './components/clients/search.jsx'; import VeloClientList from './components/clients/clients-list.jsx'; @@ -20,7 +21,6 @@ import ArtifactInspector from './components/artifacts/artifacts.jsx'; import UserInspector from './components/users/user-inspector.jsx'; import VeloHunts from './components/hunts/hunts.jsx'; import UserDashboard from './components/sidebar/user-dashboard.jsx'; -import Form from 'react-bootstrap/Form'; import UserLabel from './components/users/user-label.jsx'; import EventMonitoring from './components/events/events.jsx'; import SnackbarProvider from 'react-simple-snackbar'; @@ -31,9 +31,8 @@ import LogoffPage from './components/welcome/logoff.jsx'; import KeyboardHelp from './components/core/keyboard-help.jsx'; import { UserSettings } from './components/core/user.jsx'; import { ContextMenuPopup } from './components/utils/context.jsx'; -import { Switch, Route } from "react-router-dom"; +import { Switch, Route, withRouter } from "react-router-dom"; import { Join } from './components/utils/paths.jsx'; -import { withRouter } from "react-router-dom"; import Navbar from 'react-bootstrap/Navbar'; import Nav from 'react-bootstrap/Nav'; @@ -67,6 +66,10 @@ import './themes/midnight.css'; */ class App extends Component { + static propTypes = { + history: PropTypes.any, + } + state = { client: {}, diff --git a/gui/velociraptor/src/App.test.jsx b/gui/velociraptor/src/App.test.jsx deleted file mode 100644 index 4db7ebc25c2..00000000000 --- a/gui/velociraptor/src/App.test.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - const { getByText } = render(); - const linkElement = getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/gui/velociraptor/src/components/artifacts/artifacts-upload.jsx b/gui/velociraptor/src/components/artifacts/artifacts-upload.jsx index b41b9211e16..988d6a1365d 100644 --- a/gui/velociraptor/src/components/artifacts/artifacts-upload.jsx +++ b/gui/velociraptor/src/components/artifacts/artifacts-upload.jsx @@ -9,7 +9,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import classNames from "classnames"; import api from '../core/api-service.jsx'; import BootstrapTable from 'react-bootstrap-table-next'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import filterFactory from 'react-bootstrap-table2-filter'; import { formatColumns } from "../core/table.jsx"; import T from '../i8n/i8n.jsx'; @@ -26,7 +26,7 @@ export default class ArtifactsUpload extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/artifacts/artifacts.css b/gui/velociraptor/src/components/artifacts/artifacts.css index a4380f713f6..0f2d347933e 100644 --- a/gui/velociraptor/src/components/artifacts/artifacts.css +++ b/gui/velociraptor/src/components/artifacts/artifacts.css @@ -74,3 +74,22 @@ span.user-edit { .form-inline .artifact-search-input.form-control { width: 300px; } + +.artifact-search-table td { + padding: 0px; + margin: 0px; +} + +.link-button { + background-color: transparent; + color: var(--color-foreground); + border: none; + cursor: pointer; + display: inline; + margin: 0; + padding: 0; +} + +.built-in-icon { + padding-right: 5px; +} diff --git a/gui/velociraptor/src/components/artifacts/artifacts.jsx b/gui/velociraptor/src/components/artifacts/artifacts.jsx index 1c23ac87b1b..ff6f9a3ea31 100644 --- a/gui/velociraptor/src/components/artifacts/artifacts.jsx +++ b/gui/velociraptor/src/components/artifacts/artifacts.jsx @@ -7,7 +7,7 @@ import VeloReportViewer from "../artifacts/reporting.jsx"; import Select from 'react-select'; import _ from 'lodash'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Navbar from 'react-bootstrap/Navbar'; import ButtonGroup from 'react-bootstrap/ButtonGroup'; import Button from 'react-bootstrap/Button'; @@ -72,6 +72,10 @@ class DeleteOKDialog extends React.Component { class ArtifactInspector extends React.Component { static propTypes = { client: PropTypes.object, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { @@ -97,7 +101,7 @@ class ArtifactInspector extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.searchInput.focus(); let artifact_name = this.props.match && this.props.match.params && this.props.match.params.artifact; @@ -125,7 +129,7 @@ class ArtifactInspector extends React.Component { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.post("v1/GetArtifacts", { @@ -234,6 +238,8 @@ class ArtifactInspector extends React.Component { artifact: "name: "+selected, op: "DELETE", }, this.source.token).then(resp => { + if (resp.cancel) return; + this.fetchRows(this.state.current_filter); this.setState({showDeleteArtifactDialog: false}); }); @@ -408,17 +414,20 @@ class ArtifactInspector extends React.Component { item.name === this.state.selectedDescriptor.name ? "row-selected" : undefined }> - this.onSelect(item, e)}> - {/* eslint jsx-a11y/anchor-is-valid: "off" */} - this.onSelect(item, e)}> + + + ; })} diff --git a/gui/velociraptor/src/components/artifacts/line-charts.jsx b/gui/velociraptor/src/components/artifacts/line-charts.jsx index 40241ca9b7c..69661604ebb 100644 --- a/gui/velociraptor/src/components/artifacts/line-charts.jsx +++ b/gui/velociraptor/src/components/artifacts/line-charts.jsx @@ -25,6 +25,7 @@ class CustomTooltip extends React.Component { payload: PropTypes.array, columns: PropTypes.array, data: PropTypes.array, + active: PropTypes.any, } render() { diff --git a/gui/velociraptor/src/components/artifacts/new-artifact.jsx b/gui/velociraptor/src/components/artifacts/new-artifact.jsx index 69aef0ff08b..4b872bbfdc4 100644 --- a/gui/velociraptor/src/components/artifacts/new-artifact.jsx +++ b/gui/velociraptor/src/components/artifacts/new-artifact.jsx @@ -9,7 +9,7 @@ import VeloAce, { SettingsButton } from '../core/ace.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import T from '../i8n/i8n.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Completer from './syntax.jsx'; export default class NewArtifactDialog extends React.Component { @@ -19,7 +19,7 @@ export default class NewArtifactDialog extends React.Component { }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchArtifact(); } diff --git a/gui/velociraptor/src/components/artifacts/reporting.jsx b/gui/velociraptor/src/components/artifacts/reporting.jsx index 9d242fd0c60..d2a1b9fdc34 100644 --- a/gui/velociraptor/src/components/artifacts/reporting.jsx +++ b/gui/velociraptor/src/components/artifacts/reporting.jsx @@ -3,7 +3,7 @@ import _ from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import parse from 'html-react-parser'; import api from '../core/api-service.jsx'; @@ -33,6 +33,7 @@ export default class VeloReportViewer extends React.Component { params: PropTypes.object, client: PropTypes.object, flow_id: PropTypes.string, + refresh: PropTypes.func, } state = { @@ -44,7 +45,7 @@ export default class VeloReportViewer extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.updateReport(); } @@ -101,7 +102,7 @@ export default class VeloReportViewer extends React.Component { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.post("v1/GetReport", params, this.source.token).then((response) => { if (response.cancel) return; @@ -111,7 +112,7 @@ export default class VeloReportViewer extends React.Component { messages: response.data.messages || [], data: JSON.parse(response.data.data), loading: false, - version: this.state.version += 1, + version: this.state.version + 1, }; for (var i=0; i ); - } catch(e) { - - }; + } catch(e) {}; } if (domNode.name === "grr-csv-viewer") { diff --git a/gui/velociraptor/src/components/clients/client-link.jsx b/gui/velociraptor/src/components/clients/client-link.jsx index b66afb09a31..bfb887a9218 100644 --- a/gui/velociraptor/src/components/clients/client-link.jsx +++ b/gui/velociraptor/src/components/clients/client-link.jsx @@ -10,6 +10,9 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; class ClientLink extends React.Component { static propTypes = { client_id: PropTypes.string, + + // React router props. + history: PropTypes.object, }; link = () => { diff --git a/gui/velociraptor/src/components/clients/client-status.jsx b/gui/velociraptor/src/components/clients/client-status.jsx index 7402a9c1484..37eaa250db9 100644 --- a/gui/velociraptor/src/components/clients/client-status.jsx +++ b/gui/velociraptor/src/components/clients/client-status.jsx @@ -2,7 +2,6 @@ import "./client-status.css"; import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import api from '../core/api-service.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; export default class VeloClientStatusIcon extends Component { diff --git a/gui/velociraptor/src/components/clients/client-summary.jsx b/gui/velociraptor/src/components/clients/client-summary.jsx index adbecfcb6ea..2f9a45a97ee 100644 --- a/gui/velociraptor/src/components/clients/client-summary.jsx +++ b/gui/velociraptor/src/components/clients/client-summary.jsx @@ -3,7 +3,7 @@ import "./client-summary.css"; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import T from '../i8n/i8n.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import { Link } from "react-router-dom"; @@ -19,7 +19,7 @@ export default class VeloClientSummary extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.getClientInfo, POLL_TIME); this.getClientInfo(); } @@ -41,7 +41,7 @@ export default class VeloClientSummary extends Component { getClientInfo = () => { this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let params = {update_mru: true}; let client_id = this.props.client && this.props.client.client_id; diff --git a/gui/velociraptor/src/components/clients/client_info.jsx b/gui/velociraptor/src/components/clients/client_info.jsx index e8d543cf200..cb5bcc93535 100644 --- a/gui/velociraptor/src/components/clients/client_info.jsx +++ b/gui/velociraptor/src/components/clients/client_info.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { withRouter } from "react-router-dom"; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; // A component that syncs a client id to a client record. @@ -11,6 +11,9 @@ class ClientSetterFromRoute extends Component { static propTypes = { client: PropTypes.object, setClient: PropTypes.func.isRequired, + + // React router props. + match: PropTypes.object, } componentDidUpdate() { @@ -18,7 +21,7 @@ class ClientSetterFromRoute extends Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.maybeUpdateClientInfo(); } diff --git a/gui/velociraptor/src/components/clients/clients-list.jsx b/gui/velociraptor/src/components/clients/clients-list.jsx index 1fae87c634f..7f47b41f44f 100644 --- a/gui/velociraptor/src/components/clients/clients-list.jsx +++ b/gui/velociraptor/src/components/clients/clients-list.jsx @@ -1,6 +1,6 @@ import "./clients-list.css"; -import axios from 'axios'; +import {CancelToken} from 'axios'; import _ from 'lodash'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -41,7 +41,7 @@ export class LabelClients extends Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -152,7 +152,7 @@ class DeleteClients extends Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -313,6 +313,10 @@ class VeloClientList extends Component { version: PropTypes.any, setClient: PropTypes.func.isRequired, setSearch: PropTypes.func.isRequired, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, } state = { @@ -330,7 +334,7 @@ class VeloClientList extends Component { }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let query = this.props.match && this.props.match.params && this.props.match.params.query; if (query && query !== this.state.query) { @@ -362,7 +366,7 @@ class VeloClientList extends Component { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); api.get('/v1/SearchClients', { diff --git a/gui/velociraptor/src/components/clients/host-info.jsx b/gui/velociraptor/src/components/clients/host-info.jsx index ffd590a57f0..03e86992f1d 100644 --- a/gui/velociraptor/src/components/clients/host-info.jsx +++ b/gui/velociraptor/src/components/clients/host-info.jsx @@ -8,7 +8,6 @@ import { withRouter, Link } from "react-router-dom"; import VeloTimestamp from "../utils/time.jsx"; import ShellViewer from "./shell-viewer.jsx"; import VeloReportViewer from "../artifacts/reporting.jsx"; -import VeloForm from '../forms/form.jsx'; import { LabelClients } from './clients-list.jsx'; import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup'; @@ -22,14 +21,11 @@ import Form from 'react-bootstrap/Form'; import UserConfig from '../core/user.jsx'; import MetadataEditor from "./metadata.jsx"; import api from '../core/api-service.jsx'; -import axios from 'axios'; -import { parseCSV, serializeCSV } from '../utils/csv.jsx'; +import {CancelToken} from 'axios'; import "./host-info.css"; import { runArtifact } from "../flows/utils.jsx"; import T from '../i8n/i8n.jsx'; - -const POLL_TIME = 5000; const INTERROGATE_POLL_TIME = 2000; var quarantine_artifacts = { @@ -55,7 +51,7 @@ class QuarantineDialog extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.checkQuarantineAvailability(); } @@ -185,6 +181,10 @@ class VeloHostInfo extends Component { // We must be viewing an actual client. client: PropTypes.object, setClient: PropTypes.func.isRequired, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, } state = { @@ -198,7 +198,7 @@ class VeloHostInfo extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.updateClientInfo(); } diff --git a/gui/velociraptor/src/components/clients/metadata.jsx b/gui/velociraptor/src/components/clients/metadata.jsx index 296c870b2bc..65a416405d8 100644 --- a/gui/velociraptor/src/components/clients/metadata.jsx +++ b/gui/velociraptor/src/components/clients/metadata.jsx @@ -2,13 +2,8 @@ import _ from 'lodash'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; -import Form from 'react-bootstrap/Form'; -import Row from 'react-bootstrap/Row'; -import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; -import Tooltip from 'react-bootstrap/Tooltip'; -import Col from 'react-bootstrap/Col'; import BootstrapTable from 'react-bootstrap-table-next'; import cellEditFactory, { Type } from 'react-bootstrap-table2-editor'; import filterFactory from 'react-bootstrap-table2-filter'; @@ -21,12 +16,6 @@ import { formatColumns } from "../core/table.jsx"; const POLL_TIME = 5000; -const renderToolTip = (props, params) => ( - - {params.description} - -); - export default class MetadataEditor extends Component { static propTypes = { @@ -39,7 +28,7 @@ export default class MetadataEditor extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchMetadata, POLL_TIME); this.fetchMetadata(); } @@ -58,7 +47,7 @@ export default class MetadataEditor extends Component { this.setState({metadata_loading: true}); this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/GetClientMetadata/" + this.props.client_id, {}, this.source.token).then(response=>{ diff --git a/gui/velociraptor/src/components/clients/search.jsx b/gui/velociraptor/src/components/clients/search.jsx index a039ccda5b0..cc50b6df295 100644 --- a/gui/velociraptor/src/components/clients/search.jsx +++ b/gui/velociraptor/src/components/clients/search.jsx @@ -14,18 +14,23 @@ import Dropdown from 'react-bootstrap/Dropdown'; import UserConfig from '../core/user.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import T from '../i8n/i8n.jsx'; + class VeloClientSearch extends Component { static contextType = UserConfig; static propTypes = { // Update the applications's search parameter. setSearch: PropTypes.func.isRequired, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let query = this.props.match && this.props.match.params && this.props.match.params.query; if (query && query !== this.state.query) { @@ -90,7 +95,6 @@ class VeloClientSearch extends Component { inputProps={{ placeholder: T("SEARCH_CLIENTS"), spellCheck: "false", - id: this.props.id || "client-search-bar", value: this.state.query, onChange: (e, {newValue, method}) => { this.setState({query: newValue}); diff --git a/gui/velociraptor/src/components/clients/shell-viewer.jsx b/gui/velociraptor/src/components/clients/shell-viewer.jsx index 6ff0b9f7e90..bc39705a9f9 100644 --- a/gui/velociraptor/src/components/clients/shell-viewer.jsx +++ b/gui/velociraptor/src/components/clients/shell-viewer.jsx @@ -11,7 +11,7 @@ import T from '../i8n/i8n.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { requestToParameters } from "../flows/utils.jsx"; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import VeloTimestamp from "../utils/time.jsx"; import VeloPagedTable from "../core/paged-table.jsx"; import VeloAce from '../core/ace.jsx'; @@ -28,6 +28,9 @@ class _VeloShellCell extends Component { flow: PropTypes.object, client: PropTypes.object, fetchLastShellCollections: PropTypes.func.isRequired, + + // React router props. + history: PropTypes.object, } state = { @@ -38,7 +41,7 @@ class _VeloShellCell extends Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -293,6 +296,9 @@ class _VeloVQLCell extends Component { flow: PropTypes.object, client: PropTypes.object, fetchLastShellCollections: PropTypes.func.isRequired, + + // React router props. + history: PropTypes.object, } state = { @@ -547,7 +553,7 @@ class ShellViewer extends Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchLastShellCollections, SHELL_POLL_TIME); this.fetchLastShellCollections(); } @@ -704,9 +710,9 @@ class ShellViewer extends Component { id="bg-nested-dropdown"> Powershell { (!this.state.client_os || this.state.client_os === "windows") && - Cmd } + Cmd } { (!this.state.client_os || this.state.client_os !== "windows") && - Bash } + Bash } VQL diff --git a/gui/velociraptor/src/components/core/ace-config.jsx b/gui/velociraptor/src/components/core/ace-config.jsx index 6bb1abd75c7..a8101bcdf9b 100644 --- a/gui/velociraptor/src/components/core/ace-config.jsx +++ b/gui/velociraptor/src/components/core/ace-config.jsx @@ -1,6 +1,4 @@ import React from 'react'; -import PropTypes from 'prop-types'; - const ACEConfig = React.createContext('ace-config'); export default ACEConfig; diff --git a/gui/velociraptor/src/components/core/ace.jsx b/gui/velociraptor/src/components/core/ace.jsx index 38f0a46d657..0a0a0357051 100644 --- a/gui/velociraptor/src/components/core/ace.jsx +++ b/gui/velociraptor/src/components/core/ace.jsx @@ -92,7 +92,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import UserConfig from './user.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; export class SettingsButton extends Component { @@ -110,7 +110,7 @@ export class SettingsButton extends Component { onClick={() => this.props.ace.execCommand("showSettingsMenu")} > - {T("Configure Editor")} + {T("Configure Editor")} ); @@ -125,6 +125,7 @@ export default class VeloAce extends Component { focus: PropTypes.bool, onChange: PropTypes.func, options: PropTypes.object, + placeholder: PropTypes.string, // Extra toolbar buttons to go in the editor toolbar. toolbar: PropTypes.any, @@ -192,7 +193,7 @@ export default class VeloAce extends Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/core/api-service.jsx b/gui/velociraptor/src/components/core/api-service.jsx index 44c7734e8e2..c316a80b685 100644 --- a/gui/velociraptor/src/components/core/api-service.jsx +++ b/gui/velociraptor/src/components/core/api-service.jsx @@ -1,4 +1,4 @@ -import axios from 'axios'; +import axios, {isCancel} from 'axios'; import _ from 'lodash'; import qs from 'qs'; @@ -108,7 +108,7 @@ if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { let api_handlers = base_path + "/api/"; const handle_error = err=>{ - if (axios.isCancel(err)) { + if (isCancel(err)) { return {data: {}, cancel: true}; }; diff --git a/gui/velociraptor/src/components/core/keyboard-help.jsx b/gui/velociraptor/src/components/core/keyboard-help.jsx index c38d7774f85..86303479416 100644 --- a/gui/velociraptor/src/components/core/keyboard-help.jsx +++ b/gui/velociraptor/src/components/core/keyboard-help.jsx @@ -81,18 +81,18 @@ export default class KeyboardHelp extends React.PureComponent { let desc = spec[1]; return ( - - - {T(title)} - - { _.map(desc, (x, i)=>{ - return - - {this.renderKey(x[0])} : - - {x[1]} - ; - })} + + + {T(title)} + + { _.map(desc, (x, i)=>{ + return + + {this.renderKey(x[0])} : + + {x[1]} + ; + })} ); })} @@ -111,34 +111,36 @@ export default class KeyboardHelp extends React.PureComponent { }} /> { this.state.showHelp && <> - this.setState({showHelp: false}), - }} /> -
this.setState({showHelp: false})}> -
- - - - - - -
{T("Keyboard shortcuts")}
-
- + this.setState({showHelp: false}), + }} /> +
this.setState({showHelp: false})} + onClick={()=>this.setState({showHelp: false})}> +
+
- - - + + + + +
- { this.makeColumn(helpTextCol1)} - - { this.makeColumn(helpTextCol2)} -
{T("Keyboard shortcuts")}
+
+ + + + +
+ { this.makeColumn(helpTextCol1)} + + { this.makeColumn(helpTextCol2)} +
diff --git a/gui/velociraptor/src/components/core/paged-table.jsx b/gui/velociraptor/src/components/core/paged-table.jsx index 98b10328127..2bafda2acb8 100644 --- a/gui/velociraptor/src/components/core/paged-table.jsx +++ b/gui/velociraptor/src/components/core/paged-table.jsx @@ -7,7 +7,7 @@ import './paged-table.css'; import 'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator.min.css'; import ToolkitProvider from 'react-bootstrap-table2-toolkit/dist/react-bootstrap-table2-toolkit.min'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; @@ -161,7 +161,7 @@ class VeloPagedTable extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({page_size: this.props.initial_page_size || 10}); this.fetchRows(); @@ -293,7 +293,7 @@ class VeloPagedTable extends Component { let url = this.props.url || "v1/GetTable"; this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); api.get(url, params, this.source.token).then((response) => { @@ -347,7 +347,6 @@ class VeloPagedTable extends Component { headerFormatter = (column, colIndex) => { let icon = "sort"; let next_dir = "Ascending"; - let tooltip = "Sort Up"; let classname = "sort-element"; let sort_column = this.state.transform && this.state.transform.sort_column; let sort_dir = this.state.transform && this.state.transform.sort_direction; @@ -361,7 +360,6 @@ class VeloPagedTable extends Component { if (sort_dir === "Ascending") { icon = "arrow-up-a-z"; next_dir = "Descending"; - tooltip = "Sort Down"; } else { icon = "arrow-down-a-z"; } diff --git a/gui/velociraptor/src/components/core/table.jsx b/gui/velociraptor/src/components/core/table.jsx index 1ada55f24c8..d9b5f66e93c 100644 --- a/gui/velociraptor/src/components/core/table.jsx +++ b/gui/velociraptor/src/components/core/table.jsx @@ -555,6 +555,12 @@ export function formatColumns(columns, env, column_formatter) { case "preview_upload": case "upload_preview": x.formatter = (cell, row) => { + if(!env.client_id && row.ClientId) { + env.client_id = row.ClientId; + } + if(!env.flow_id && row.FlowId) { + env.flow_id = row.FlowId; + } return ; diff --git a/gui/velociraptor/src/components/core/user.jsx b/gui/velociraptor/src/components/core/user.jsx index f9d1fd49c1b..563db526225 100644 --- a/gui/velociraptor/src/components/core/user.jsx +++ b/gui/velociraptor/src/components/core/user.jsx @@ -1,7 +1,8 @@ import _ from 'lodash'; import React from 'react'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; +import PropTypes from 'prop-types'; const UserConfig = React.createContext({ traits: {}, @@ -12,6 +13,10 @@ const POLL_TIME = 5000; // A component which maintains the user settings export class UserSettings extends React.Component { + static propTypes = { + children: PropTypes.node, + } + updateTraits = () => { api.get("v1/GetUserUITraits", {}, this.source.token).then((response) => { let traits = response.data.interface_traits; @@ -55,7 +60,7 @@ export class UserSettings extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.updateTraits, POLL_TIME); this.updateTraits(); } diff --git a/gui/velociraptor/src/components/events/delete.jsx b/gui/velociraptor/src/components/events/delete.jsx index 2eda6e17bb0..b3d19bca65f 100644 --- a/gui/velociraptor/src/components/events/delete.jsx +++ b/gui/velociraptor/src/components/events/delete.jsx @@ -18,6 +18,7 @@ export default class DeleteTimelineRanges extends Component { start_time: PropTypes.number, end_time: PropTypes.number, onClose: PropTypes.func.isRequired, + artifact: PropTypes.string, } deleteData = () => { diff --git a/gui/velociraptor/src/components/events/event-notebook.jsx b/gui/velociraptor/src/components/events/event-notebook.jsx index 9f962b64a59..1989e339c4e 100644 --- a/gui/velociraptor/src/components/events/event-notebook.jsx +++ b/gui/velociraptor/src/components/events/event-notebook.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import NotebookRenderer from '../notebooks/notebook-renderer.jsx'; import _ from 'lodash'; @@ -26,7 +26,7 @@ export default class EventNotebook extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebooks, POLL_TIME); this.fetchNotebooks(); } diff --git a/gui/velociraptor/src/components/events/event-table.jsx b/gui/velociraptor/src/components/events/event-table.jsx index a6f24ea5f1b..ac06d07a2f6 100644 --- a/gui/velociraptor/src/components/events/event-table.jsx +++ b/gui/velociraptor/src/components/events/event-table.jsx @@ -14,7 +14,7 @@ import Table from 'react-bootstrap/Table'; import utils from './utils.jsx'; import { HotKeys, ObserveKeys } from "react-hotkeys"; import { Typeahead, Token } from 'react-bootstrap-typeahead'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import "react-bootstrap-typeahead/css/Typeahead.css"; @@ -47,7 +47,7 @@ class EventTableLabelGroup extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.loadLabels(); } @@ -113,7 +113,7 @@ class EventTableLabelGroup extends React.Component { } render() { - let current_label = this.props.label; + let current_label = this.props.current_label; let current_artifacts = this.props.tables && this.props.tables[current_label.label] && this.props.tables[current_label.label].artifacts; @@ -133,7 +133,6 @@ class EventTableLabelGroup extends React.Component { ( @@ -185,7 +184,7 @@ class EventTableLabelGroup extends React.Component { { this.props.paginator.makePaginator({ props: this.props, step_name: "Offline Collector", - isFocused: _.isEmpty(this.props.label), + isFocused: _.isEmpty(this.props.current_label), }) } @@ -215,7 +214,7 @@ export class EventTableWizard extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchEventTable(); } @@ -340,7 +339,7 @@ export class EventTableWizard extends React.Component { this.step=n}> { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchEventTable(); } diff --git a/gui/velociraptor/src/components/events/events.jsx b/gui/velociraptor/src/components/events/events.jsx index 17e808c1ef5..57f24ff73ae 100644 --- a/gui/velociraptor/src/components/events/events.jsx +++ b/gui/velociraptor/src/components/events/events.jsx @@ -2,7 +2,7 @@ import './events.css'; import React from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import _ from 'lodash'; import Navbar from 'react-bootstrap/Navbar'; import ButtonGroup from 'react-bootstrap/ButtonGroup'; @@ -40,7 +40,7 @@ class InspectRawJson extends React.PureComponent { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchEventTable(); } @@ -59,7 +59,7 @@ class InspectRawJson extends React.PureComponent { fetchEventTable = () => { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); // The same file is used by both server and client event // tables - only difference is that the server's client id is @@ -163,10 +163,14 @@ const getLogArtifact = function (logs, router_artifact) { class EventMonitoring extends React.Component { static propTypes = { client: PropTypes.object, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchEventResults(); } @@ -221,7 +225,7 @@ class EventMonitoring extends React.Component { fetchEventResults = () => { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let client_id = this.props.client.client_id || "server"; api.post("v1/ListAvailableEventResults", { @@ -307,7 +311,7 @@ class EventMonitoring extends React.Component { onClick={() => this.setState({showServerEventTableWizard: true})} variant="default"> - {T("Update server monitoring tables")} + {T("Update server monitoring tables")} : @@ -326,7 +330,7 @@ class EventMonitoring extends React.Component { onClick={() => this.setState({showEventTableWizard: true})} variant="default"> - {T("Update client monitoring table")} + {T("Update client monitoring table")} } @@ -376,7 +380,7 @@ class EventMonitoring extends React.Component { onClick={() => this.setState({showDeleteNotebook: true})} variant="default"> - {T("Delete Notebook")} + {T("Delete Notebook")} } diff --git a/gui/velociraptor/src/components/events/timeline-viewer.jsx b/gui/velociraptor/src/components/events/timeline-viewer.jsx index 029e2a711f7..35fd22ef516 100644 --- a/gui/velociraptor/src/components/events/timeline-viewer.jsx +++ b/gui/velociraptor/src/components/events/timeline-viewer.jsx @@ -9,7 +9,7 @@ import Timeline, { } from 'react-calendar-timeline'; import moment from 'moment'; import 'moment-timezone'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import { PrepareData } from '../core/table.jsx'; import api from '../core/api-service.jsx'; import BootstrapTable from 'react-bootstrap-table-next'; @@ -137,8 +137,8 @@ export default class EventTimelineViewer extends React.Component { }; componentDidMount = () => { - this.source = axios.CancelToken.source(); - this.ts_source = axios.CancelToken.source(); + this.source = CancelToken.source(); + this.ts_source = CancelToken.source(); this.fetchAvailableTimes(); } @@ -177,7 +177,7 @@ export default class EventTimelineViewer extends React.Component { fetchAvailableTimes = () => { this.ts_source.cancel(); - this.ts_source = axios.CancelToken.source(); + this.ts_source = CancelToken.source(); let client_id = this.props.client_id || "server"; @@ -211,10 +211,10 @@ export default class EventTimelineViewer extends React.Component { } fetchRows = () => { - let url = this.props.url || "v1/GetTable"; + let url = "v1/GetTable"; this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); diff --git a/gui/velociraptor/src/components/flows/client-flows-view.jsx b/gui/velociraptor/src/components/flows/client-flows-view.jsx index cfa7c3a3054..46c09a61d48 100644 --- a/gui/velociraptor/src/components/flows/client-flows-view.jsx +++ b/gui/velociraptor/src/components/flows/client-flows-view.jsx @@ -9,7 +9,7 @@ import FlowInspector from "./flows-inspector.jsx"; import { withRouter } from "react-router-dom"; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Spinner from '../utils/spinner.jsx'; const POLL_TIME = 5000; @@ -17,6 +17,10 @@ const POLL_TIME = 5000; class ClientFlowsView extends React.Component { static propTypes = { client: PropTypes.object, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { @@ -28,7 +32,7 @@ class ClientFlowsView extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchFlows, POLL_TIME); this.fetchFlows(); } @@ -55,7 +59,7 @@ class ClientFlowsView extends React.Component { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/GetClientFlows/" + client_id, { count: 1000, diff --git a/gui/velociraptor/src/components/flows/flow-full-notebook.jsx b/gui/velociraptor/src/components/flows/flow-full-notebook.jsx index eb7ea85aed3..8b6065d11f0 100644 --- a/gui/velociraptor/src/components/flows/flow-full-notebook.jsx +++ b/gui/velociraptor/src/components/flows/flow-full-notebook.jsx @@ -1,4 +1,6 @@ import React from 'react'; +import PropTypes from 'prop-types'; + import T from '../i8n/i8n.jsx'; import FlowNotebook from './flow-notebook.jsx'; import { withRouter } from "react-router-dom"; @@ -10,7 +12,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; class FullScreenFlowNotebook extends React.Component { - static propTypes = {}; + static propTypes = { + // React router props. + match: PropTypes.object, + history: PropTypes.object, + }; state = {}; diff --git a/gui/velociraptor/src/components/flows/flow-link.jsx b/gui/velociraptor/src/components/flows/flow-link.jsx index 9653a14d4e0..caf8b4f8f46 100644 --- a/gui/velociraptor/src/components/flows/flow-link.jsx +++ b/gui/velociraptor/src/components/flows/flow-link.jsx @@ -13,7 +13,7 @@ import FlowOverview from './flow-overview.jsx'; import FlowUploads from './flow-uploads.jsx'; import FlowResults from './flow-results.jsx'; import FlowLogs from './flow-logs.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; class FlowPopupInspector extends React.Component { static propTypes = { @@ -71,7 +71,7 @@ export default class FlowLink extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/flows/flow-notebook.jsx b/gui/velociraptor/src/components/flows/flow-notebook.jsx index dac47cef030..73a8b630b2e 100644 --- a/gui/velociraptor/src/components/flows/flow-notebook.jsx +++ b/gui/velociraptor/src/components/flows/flow-notebook.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import NotebookRenderer from '../notebooks/notebook-renderer.jsx'; import _ from 'lodash'; @@ -19,7 +19,7 @@ export default class FlowNotebook extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebooks, POLL_TIME); this.fetchNotebooks(); } @@ -59,7 +59,7 @@ export default class FlowNotebook extends React.Component { let notebook_id = "N." + flow_id + "-" + client_id; this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); api.get("v1/GetNotebooks", { diff --git a/gui/velociraptor/src/components/flows/flow-overview.jsx b/gui/velociraptor/src/components/flows/flow-overview.jsx index 110f466d961..fc094a52dc1 100644 --- a/gui/velociraptor/src/components/flows/flow-overview.jsx +++ b/gui/velociraptor/src/components/flows/flow-overview.jsx @@ -15,7 +15,7 @@ import Tooltip from 'react-bootstrap/Tooltip'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import T from '../i8n/i8n.jsx'; import _ from 'lodash'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import AvailableDownloads from "../notebooks/downloads.jsx"; import api from '../core/api-service.jsx'; @@ -31,7 +31,7 @@ export default class FlowOverview extends React.Component { }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.getDetailedFlow, POLL_TIME); this.getDetailedFlow(); diff --git a/gui/velociraptor/src/components/flows/flow-requests.jsx b/gui/velociraptor/src/components/flows/flow-requests.jsx index b25cf7d0569..d3f09bc56ce 100644 --- a/gui/velociraptor/src/components/flows/flow-requests.jsx +++ b/gui/velociraptor/src/components/flows/flow-requests.jsx @@ -4,7 +4,7 @@ import T from '../i8n/i8n.jsx'; import VeloAce from '../core/ace.jsx'; import CardDeck from 'react-bootstrap/CardDeck'; import Card from 'react-bootstrap/Card'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; export default class FlowRequests extends React.Component { @@ -17,7 +17,7 @@ export default class FlowRequests extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchRequests(); } diff --git a/gui/velociraptor/src/components/flows/flow-uploads.jsx b/gui/velociraptor/src/components/flows/flow-uploads.jsx index b90aba25b2b..0fe67ec7420 100644 --- a/gui/velociraptor/src/components/flows/flow-uploads.jsx +++ b/gui/velociraptor/src/components/flows/flow-uploads.jsx @@ -1,15 +1,7 @@ -import _ from 'lodash'; - import React from 'react'; import PropTypes from 'prop-types'; import Button from 'react-bootstrap/Button'; -import axios from 'axios'; -import { PrepareData } from '../core/table.jsx'; import VeloPagedTable from '../core/paged-table.jsx'; -import T from '../i8n/i8n.jsx'; -import Spinner from '../utils/spinner.jsx'; -import CardDeck from 'react-bootstrap/CardDeck'; -import Card from 'react-bootstrap/Card'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; import Tooltip from 'react-bootstrap/Tooltip'; diff --git a/gui/velociraptor/src/components/flows/flows-add-to-hunt.jsx b/gui/velociraptor/src/components/flows/flows-add-to-hunt.jsx index bfadd8c7eba..2c4652afc1a 100644 --- a/gui/velociraptor/src/components/flows/flows-add-to-hunt.jsx +++ b/gui/velociraptor/src/components/flows/flows-add-to-hunt.jsx @@ -9,7 +9,7 @@ import BootstrapTable from 'react-bootstrap-table-next'; import { formatColumns } from "../core/table.jsx"; import ArtifactLink from '../artifacts/artifacts-link.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import { runArtifact } from "./utils.jsx"; @@ -27,7 +27,7 @@ export default class AddFlowToHuntDialog extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchCompatibleHunts(); } diff --git a/gui/velociraptor/src/components/flows/flows-inspector.jsx b/gui/velociraptor/src/components/flows/flows-inspector.jsx index 12eb939cf25..14a5d8494a9 100644 --- a/gui/velociraptor/src/components/flows/flows-inspector.jsx +++ b/gui/velociraptor/src/components/flows/flows-inspector.jsx @@ -14,13 +14,17 @@ import { withRouter } from "react-router-dom"; // Typically subclassable by actual components. import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; const POLL_TIME = 5000; class FlowInspector extends React.Component { static propTypes = { flow: PropTypes.object, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { @@ -29,7 +33,7 @@ class FlowInspector extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchDetailedFlow, POLL_TIME); // Set the abbreviated flow in the meantime while we fetch the @@ -68,7 +72,7 @@ class FlowInspector extends React.Component { // Cancel any in flight requests. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); api.get("v1/GetFlowDetails", { diff --git a/gui/velociraptor/src/components/flows/flows-list.jsx b/gui/velociraptor/src/components/flows/flows-list.jsx index 2d6308e3dd8..0b80051d442 100644 --- a/gui/velociraptor/src/components/flows/flows-list.jsx +++ b/gui/velociraptor/src/components/flows/flows-list.jsx @@ -1,4 +1,3 @@ - import "./flows.css"; import React from 'react'; @@ -31,7 +30,7 @@ import UserConfig from '../core/user.jsx'; import VeloForm from '../forms/form.jsx'; import AddFlowToHuntDialog from './flows-add-to-hunt.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; export class DeleteFlowDialog extends React.PureComponent { @@ -46,7 +45,7 @@ export class DeleteFlowDialog extends React.PureComponent { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -110,7 +109,7 @@ export class SaveCollectionDialog extends React.PureComponent { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -182,6 +181,10 @@ class FlowsList extends React.Component { setSelectedFlow: PropTypes.func, selected_flow: PropTypes.object, fetchFlows: PropTypes.func, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { @@ -195,7 +198,7 @@ class FlowsList extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let action = this.props.match && this.props.match.params && this.props.match.params.flow_id; @@ -466,7 +469,7 @@ class FlowsList extends React.Component { onClick={() => this.setState({showWizard: true})} variant="default"> - {T("New Collection")} + {T("New Collection")} { client_id !== "server" && @@ -476,7 +479,7 @@ class FlowsList extends React.Component { onClick={()=>this.setState({showAddToHunt: true})} variant="default"> - {T("Add to hunt")} + {T("Add to hunt")} } { isServer && @@ -525,7 +528,7 @@ class FlowsList extends React.Component { onClick={() => this.setState({showOfflineWizard: true})} variant="default"> - {T("Build offline collector")} + {T("Build offline collector")} } @@ -538,7 +541,7 @@ class FlowsList extends React.Component { disabled={true} variant="outline-dark"> - {T("Notebooks")} + {T("Notebooks")} diff --git a/gui/velociraptor/src/components/flows/new-collection.jsx b/gui/velociraptor/src/components/flows/new-collection.jsx index 02bb4e01808..ae67f857b2a 100644 --- a/gui/velociraptor/src/components/flows/new-collection.jsx +++ b/gui/velociraptor/src/components/flows/new-collection.jsx @@ -30,7 +30,7 @@ import { HotKeys, ObserveKeys } from "react-hotkeys"; import { requestToParameters, runArtifact } from "./utils.jsx"; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; class PaginationBuilder { PaginationSteps = ["Select Artifacts", "Configure Parameters", @@ -129,7 +129,7 @@ class NewCollectionSelectArtifacts extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.doSearch("..."); } @@ -137,6 +137,14 @@ class NewCollectionSelectArtifacts extends React.Component { this.source.cancel(); } + // Trigger a selection of the first artifacts when the list is + // added. This will render the artifact description view. + componentDidUpdate = (prevProps, prevState, rootNode) => { + if(_.isEmpty(prevProps.artifacts) && !_.isEmpty(this.props.artifacts)) { + this.onSelect(this.props.artifacts[0], true); + } + } + onSelect = (row, isSelect) => { // The row contains only the name so we need to make another // request to fetch the full definition. @@ -681,7 +689,7 @@ class NewCollectionLaunch extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -796,10 +804,11 @@ class NewCollectionWizard extends React.Component { baseFlow: PropTypes.object, onResolve: PropTypes.func, onCancel: PropTypes.func, + client: PropTypes.object, } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.initializeFromBaseFlow(); // A bit hacky but whatevs... diff --git a/gui/velociraptor/src/components/flows/offline-collector.jsx b/gui/velociraptor/src/components/flows/offline-collector.jsx index fcad90dda3d..ed01c79669d 100644 --- a/gui/velociraptor/src/components/flows/offline-collector.jsx +++ b/gui/velociraptor/src/components/flows/offline-collector.jsx @@ -40,6 +40,7 @@ class OfflineCollectorParameters extends React.Component { static propTypes = { parameters: PropTypes.object, setParameters: PropTypes.func.isRequired, + paginator: PropTypes.object, } render() { diff --git a/gui/velociraptor/src/components/flows/server-flows-view.jsx b/gui/velociraptor/src/components/flows/server-flows-view.jsx index 475d7b8a4a3..3499106344d 100644 --- a/gui/velociraptor/src/components/flows/server-flows-view.jsx +++ b/gui/velociraptor/src/components/flows/server-flows-view.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import SplitPane from 'react-split-pane'; import _ from 'lodash'; @@ -7,12 +8,15 @@ import FlowInspector from "./flows-inspector.jsx"; import { withRouter } from "react-router-dom"; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; const POLL_TIME = 5000; class ServerFlowsView extends React.Component { static propTypes = { + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { @@ -21,7 +25,7 @@ class ServerFlowsView extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchFlows, POLL_TIME); this.fetchFlows(); } @@ -37,7 +41,7 @@ class ServerFlowsView extends React.Component { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/GetClientFlows/server", { count: 100, diff --git a/gui/velociraptor/src/components/forms/form.jsx b/gui/velociraptor/src/components/forms/form.jsx index 0c5f85f2db2..82928560865 100644 --- a/gui/velociraptor/src/components/forms/form.jsx +++ b/gui/velociraptor/src/components/forms/form.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import api from '../core/api-service.jsx'; import _ from 'lodash'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import DateTimePicker from 'react-datetime-picker'; import Form from 'react-bootstrap/Form'; import Row from 'react-bootstrap/Row'; @@ -82,7 +82,7 @@ export default class VeloForm extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.maybeFetchArtifacts(this.props.param.artifact_type); } @@ -107,7 +107,7 @@ export default class VeloForm extends React.Component { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); // Load all artifacts, but only keep the ones that match the // specified type @@ -249,7 +249,7 @@ export default class VeloForm extends React.Component { case "hidden": return <>; - case "csv": + case "csv": { let data = parseCSV(this.props.value); let columns = [{ dataField: "_id", @@ -346,6 +346,7 @@ export default class VeloForm extends React.Component { ); + } case "regex": return ( @@ -410,7 +411,7 @@ export default class VeloForm extends React.Component { ); - case "timestamp": + case "timestamp": { // value prop is always a string in ISO format in UTC timezone. let date = convertToDate(this.props.value); @@ -470,6 +471,7 @@ export default class VeloForm extends React.Component { ); + } case "choices": return ( diff --git a/gui/velociraptor/src/components/hunts/estimate.jsx b/gui/velociraptor/src/components/hunts/estimate.jsx index 065281e31be..7824a2c70e3 100644 --- a/gui/velociraptor/src/components/hunts/estimate.jsx +++ b/gui/velociraptor/src/components/hunts/estimate.jsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import Alert from 'react-bootstrap/Alert'; import Form from 'react-bootstrap/Form'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import './estimate.css'; @@ -17,7 +17,7 @@ export default class EstimateHunt extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchEstimate(); } diff --git a/gui/velociraptor/src/components/hunts/hunt-full-notebook.jsx b/gui/velociraptor/src/components/hunts/hunt-full-notebook.jsx index 63081dc2a72..e96780c1ade 100644 --- a/gui/velociraptor/src/components/hunts/hunt-full-notebook.jsx +++ b/gui/velociraptor/src/components/hunts/hunt-full-notebook.jsx @@ -1,4 +1,6 @@ import React from 'react'; +import PropTypes from 'prop-types'; + import HuntNotebook from './hunt-notebook.jsx'; import { withRouter } from "react-router-dom"; @@ -9,7 +11,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import T from '../i8n/i8n.jsx'; class FullScreenHuntNotebook extends React.Component { - static propTypes = {}; + static propTypes = { + // React router props. + match: PropTypes.object, + history: PropTypes.object, + }; state = {}; diff --git a/gui/velociraptor/src/components/hunts/hunt-inspector.jsx b/gui/velociraptor/src/components/hunts/hunt-inspector.jsx index 4c3f8de69bb..ac510c72a6c 100644 --- a/gui/velociraptor/src/components/hunts/hunt-inspector.jsx +++ b/gui/velociraptor/src/components/hunts/hunt-inspector.jsx @@ -16,6 +16,10 @@ class HuntInspector extends React.Component { static propTypes = { hunt: PropTypes.object, fetch_hunts: PropTypes.func, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { diff --git a/gui/velociraptor/src/components/hunts/hunt-list.jsx b/gui/velociraptor/src/components/hunts/hunt-list.jsx index 87dc8eba767..b3dc2f175b0 100644 --- a/gui/velociraptor/src/components/hunts/hunt-list.jsx +++ b/gui/velociraptor/src/components/hunts/hunt-list.jsx @@ -22,7 +22,7 @@ import T from '../i8n/i8n.jsx'; import UserConfig from '../core/user.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; class HuntList extends React.Component { @@ -36,10 +36,14 @@ class HuntList extends React.Component { hunts: PropTypes.array, setSelectedHunt: PropTypes.func, updateHunts: PropTypes.func, + + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let action = this.props.match && this.props.match.params && this.props.match.params.hunt_id; @@ -480,8 +484,9 @@ class HuntList extends React.Component { })} /> {_.isEmpty(this.props.hunts) && -
{T("No hunts exist in the system. You can start a new hunt by clicking the New Hunt button above.")}
} +
+ {T("No hunts exist in the system. You can start a new hunt by clicking the New Hunt button above.")} +
}
); diff --git a/gui/velociraptor/src/components/hunts/hunt-notebook.jsx b/gui/velociraptor/src/components/hunts/hunt-notebook.jsx index d337877e8a1..a44c6cd9096 100644 --- a/gui/velociraptor/src/components/hunts/hunt-notebook.jsx +++ b/gui/velociraptor/src/components/hunts/hunt-notebook.jsx @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import NotebookRenderer from '../notebooks/notebook-renderer.jsx'; import _ from 'lodash'; @@ -20,7 +20,7 @@ export default class HuntNotebook extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebooks, POLL_TIME); this.fetchNotebooks(); } diff --git a/gui/velociraptor/src/components/hunts/hunt-overview.jsx b/gui/velociraptor/src/components/hunts/hunt-overview.jsx index 66f473ba26e..20ef163041d 100644 --- a/gui/velociraptor/src/components/hunts/hunt-overview.jsx +++ b/gui/velociraptor/src/components/hunts/hunt-overview.jsx @@ -18,7 +18,7 @@ import T from '../i8n/i8n.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import { requestToParameters } from "../flows/utils.jsx"; import AvailableDownloads from "../notebooks/downloads.jsx"; @@ -37,7 +37,7 @@ export default class HuntOverview extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); // Default state of the lock is set by the user's preferences. let lock_password = this.context.traits && diff --git a/gui/velociraptor/src/components/hunts/hunts.jsx b/gui/velociraptor/src/components/hunts/hunts.jsx index a3bda666cf3..d8db4584e88 100644 --- a/gui/velociraptor/src/components/hunts/hunts.jsx +++ b/gui/velociraptor/src/components/hunts/hunts.jsx @@ -1,11 +1,13 @@ import React from 'react'; +import PropTypes from 'prop-types'; + import SplitPane from 'react-split-pane'; import HuntList from './hunt-list.jsx'; import HuntInspector from './hunt-inspector.jsx'; import _ from 'lodash'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Spinner from '../utils/spinner.jsx'; import { withRouter } from "react-router-dom"; @@ -14,7 +16,9 @@ const POLL_TIME = 5000; class VeloHunts extends React.Component { static propTypes = { - + // React router props. + match: PropTypes.object, + history: PropTypes.object, }; state = { @@ -34,8 +38,8 @@ class VeloHunts extends React.Component { } componentDidMount = () => { - this.get_hunts_source = axios.CancelToken.source(); - this.list_hunts_source = axios.CancelToken.source(); + this.get_hunts_source = CancelToken.source(); + this.list_hunts_source = CancelToken.source(); this.interval = setInterval(this.fetchHunts, POLL_TIME); this.fetchHunts(); } @@ -62,7 +66,7 @@ class VeloHunts extends React.Component { loadFullHunt = (hunt) => { this.setState({selected_hunt: hunt}); this.get_hunts_source.cancel(); - this.get_hunts_source = axios.CancelToken.source(); + this.get_hunts_source = CancelToken.source(); this.setState({full_selected_hunt: {loading: true}}); api.get("v1/GetHunt", { @@ -89,7 +93,7 @@ class VeloHunts extends React.Component { this.props.match.params.hunt_id; this.list_hunts_source.cancel(); - this.list_hunts_source = axios.CancelToken.source(); + this.list_hunts_source = CancelToken.source(); // Some users have a lot of hunts and listing that many might // be prohibitively expensive. @@ -134,7 +138,7 @@ class VeloHunts extends React.Component { // hunt stats are updated. if (selected_hunt_id && selected_hunt_id[0] === "H") { this.get_hunts_source.cancel(); - this.get_hunts_source = axios.CancelToken.source(); + this.get_hunts_source = CancelToken.source(); api.get("v1/GetHunt", { hunt_id: selected_hunt_id, diff --git a/gui/velociraptor/src/components/hunts/new-hunt.jsx b/gui/velociraptor/src/components/hunts/new-hunt.jsx index 13f7380dc87..1461629a332 100644 --- a/gui/velociraptor/src/components/hunts/new-hunt.jsx +++ b/gui/velociraptor/src/components/hunts/new-hunt.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import _ from 'lodash'; import Modal from 'react-bootstrap/Modal'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import StepWizard from 'react-step-wizard'; import T from '../i8n/i8n.jsx'; @@ -218,7 +218,7 @@ export default class NewHuntWizard extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let state = this.setStateFromBase(this.props.baseHunt || {}); this.setState(state); diff --git a/gui/velociraptor/src/components/i8n/en.jsx b/gui/velociraptor/src/components/i8n/en.jsx index 87efe107897..7f7b5107a71 100644 --- a/gui/velociraptor/src/components/i8n/en.jsx +++ b/gui/velociraptor/src/components/i8n/en.jsx @@ -228,6 +228,7 @@ const English = { "Perm_FILESYSTEM_WRITE" : "Filesystem Write", "Perm_MACHINE_STATE" : "Machine State", "Perm_PREPARE_RESULTS" : "Prepare Results", + "Perm_DELETE_RESULTS" : "Delete Results", "Perm_DATASTORE_ACCESS" : "Datastore Access", @@ -250,11 +251,9 @@ const English = { "ToolPerm_FILESYSTEM_WRITE" : "Allowed to create files on the filesystem", "ToolPerm_MACHINE_STATE" : "Allowed to collect state information from machines (e.g. pslist())", "ToolPerm_PREPARE_RESULTS" : "Allowed to create zip files", + "ToolPerm_DELETE_RESULTS" : "Allowed to delete clients, flows and other data", "ToolPerm_DATASTORE_ACCESS" : " Allowed raw datastore access", - - - "ToolUsernamePasswordless" : <> This server is configured to authenticate users using an external authentication host. This account must exist on the authentication system for login to be successful. diff --git a/gui/velociraptor/src/components/notebooks/add-cell-from-flow.jsx b/gui/velociraptor/src/components/notebooks/add-cell-from-flow.jsx index 13f17248f55..00c57a4e3c4 100644 --- a/gui/velociraptor/src/components/notebooks/add-cell-from-flow.jsx +++ b/gui/velociraptor/src/components/notebooks/add-cell-from-flow.jsx @@ -11,7 +11,7 @@ import T from '../i8n/i8n.jsx'; import { getClientColumns } from '../clients/clients-list.jsx'; import { getFlowColumns } from '../flows/flows-list.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; export default class AddCellFromFlowDialog extends React.Component { @@ -21,7 +21,7 @@ export default class AddCellFromFlowDialog extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setSearch("all"); } diff --git a/gui/velociraptor/src/components/notebooks/create-artifact-from-cell.jsx b/gui/velociraptor/src/components/notebooks/create-artifact-from-cell.jsx index 17ca5d6beb3..d031165f41e 100644 --- a/gui/velociraptor/src/components/notebooks/create-artifact-from-cell.jsx +++ b/gui/velociraptor/src/components/notebooks/create-artifact-from-cell.jsx @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Modal from 'react-bootstrap/Modal'; import Button from 'react-bootstrap/Button'; import ButtonGroup from 'react-bootstrap/ButtonGroup'; @@ -46,7 +46,7 @@ export default class CreateArtifactFromCell extends React.Component { // Create an artifact template from the VQL componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let lines = _.map(this.props.vql.match(/[^\r\n]+/g), line=>" "+line); this.setState({text: artifact_template + lines.join("\n")}); } diff --git a/gui/velociraptor/src/components/notebooks/export-notebook.jsx b/gui/velociraptor/src/components/notebooks/export-notebook.jsx index cbe235daae2..d93232e22c4 100644 --- a/gui/velociraptor/src/components/notebooks/export-notebook.jsx +++ b/gui/velociraptor/src/components/notebooks/export-notebook.jsx @@ -11,7 +11,7 @@ import BootstrapTable from 'react-bootstrap-table-next'; import { formatColumns } from "../core/table.jsx"; import filterFactory from 'react-bootstrap-table2-filter'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import T from '../i8n/i8n.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -30,7 +30,7 @@ export default class ExportNotebook extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebookDetails, POLL_TIME); // Set the abbreviated notebook in the meantime while we fetch the diff --git a/gui/velociraptor/src/components/notebooks/full_notebook.jsx b/gui/velociraptor/src/components/notebooks/full_notebook.jsx index 5107749fbdd..779378c6b26 100644 --- a/gui/velociraptor/src/components/notebooks/full_notebook.jsx +++ b/gui/velociraptor/src/components/notebooks/full_notebook.jsx @@ -1,10 +1,12 @@ import React from 'react'; +import PropTypes from 'prop-types'; + import NotebookRenderer from './notebook-renderer.jsx'; import Navbar from 'react-bootstrap/Navbar'; import ButtonGroup from 'react-bootstrap/ButtonGroup'; import Button from 'react-bootstrap/Button'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import Spinner from '../utils/spinner.jsx'; import { withRouter } from "react-router-dom"; @@ -15,6 +17,12 @@ const POLL_TIME = 5000; const PAGE_SIZE = 100; class FullScreenNotebook extends React.Component { + static propTypes = { + // React router props. + match: PropTypes.object, + history: PropTypes.object, + } + state = { notebooks: [], selected_notebook: {}, @@ -25,7 +33,7 @@ class FullScreenNotebook extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebooks, POLL_TIME); this.fetchNotebooks(); } @@ -38,7 +46,7 @@ class FullScreenNotebook extends React.Component { fetchNotebooks = () => { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/GetNotebooks", { count: PAGE_SIZE, diff --git a/gui/velociraptor/src/components/notebooks/notebook-cell-renderer.jsx b/gui/velociraptor/src/components/notebooks/notebook-cell-renderer.jsx index 6444c071dac..fcda14ffa8d 100644 --- a/gui/velociraptor/src/components/notebooks/notebook-cell-renderer.jsx +++ b/gui/velociraptor/src/components/notebooks/notebook-cell-renderer.jsx @@ -26,7 +26,7 @@ import { AddTimelineDialog, AddVQLCellToTimeline } from "./timelines.jsx"; import T from '../i8n/i8n.jsx'; import ViewCellLogs from "./logs.jsx"; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; const cell_types = ["Markdown", "VQL"]; @@ -58,7 +58,7 @@ class AddCellFromHunt extends React.PureComponent { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/ListHunts", { count: 100, offset: 0, @@ -175,7 +175,7 @@ export default class NotebookCellRenderer extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchCellContents(); } @@ -220,7 +220,7 @@ export default class NotebookCellRenderer extends React.Component { fetchCellContents = () => { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/GetNotebookCell", { notebook_id: this.props.notebook_id, @@ -760,9 +760,16 @@ export default class NotebookCellRenderer extends React.Component { }
-
{this.props.setSelectedCellId(this.state.cell.cell_id);}} +
this.props.setSelectedCellId( + this.state.cell.cell_id)} + onClick={()=>this.props.setSelectedCellId( + this.state.cell.cell_id)} > { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchRows(); } @@ -48,7 +48,7 @@ export class NotebookLineChart extends React.Component { let url = "v1/GetTable"; this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get(url, params, this.source.token).then((response) => { if (response.cancel) { diff --git a/gui/velociraptor/src/components/notebooks/notebook-delete.jsx b/gui/velociraptor/src/components/notebooks/notebook-delete.jsx index bd3b879ca1e..0d2e8e51082 100644 --- a/gui/velociraptor/src/components/notebooks/notebook-delete.jsx +++ b/gui/velociraptor/src/components/notebooks/notebook-delete.jsx @@ -4,7 +4,7 @@ import { runArtifact } from "../flows/utils.jsx"; import Modal from 'react-bootstrap/Modal'; import Spinner from '../utils/spinner.jsx'; import Button from 'react-bootstrap/Button'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import T from '../i8n/i8n.jsx'; @@ -19,7 +19,7 @@ export default class DeleteNotebookDialog extends React.PureComponent { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/notebooks/notebook-renderer.jsx b/gui/velociraptor/src/components/notebooks/notebook-renderer.jsx index c817976d24c..b737a1086f8 100644 --- a/gui/velociraptor/src/components/notebooks/notebook-renderer.jsx +++ b/gui/velociraptor/src/components/notebooks/notebook-renderer.jsx @@ -7,7 +7,7 @@ import _ from 'lodash'; import T from '../i8n/i8n.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; export default class NotebookRenderer extends React.Component { static propTypes = { @@ -27,7 +27,7 @@ export default class NotebookRenderer extends React.Component { componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/notebooks/notebook-uploads.jsx b/gui/velociraptor/src/components/notebooks/notebook-uploads.jsx index f2e33c9ac7a..0c0b97dfb40 100644 --- a/gui/velociraptor/src/components/notebooks/notebook-uploads.jsx +++ b/gui/velociraptor/src/components/notebooks/notebook-uploads.jsx @@ -9,7 +9,7 @@ import { formatColumns } from "../core/table.jsx"; import filterFactory from 'react-bootstrap-table2-filter'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import T from '../i8n/i8n.jsx'; const POLL_TIME = 5000; @@ -25,7 +25,7 @@ export default class NotebookUploads extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebookDetails, POLL_TIME); // Set the abbreviated notebook in the meantime while we fetch the diff --git a/gui/velociraptor/src/components/notebooks/notebook.jsx b/gui/velociraptor/src/components/notebooks/notebook.jsx index b572b044fa8..86ff827c816 100644 --- a/gui/velociraptor/src/components/notebooks/notebook.jsx +++ b/gui/velociraptor/src/components/notebooks/notebook.jsx @@ -1,11 +1,12 @@ import React from 'react'; +import PropTypes from 'prop-types'; import NotebooksList from './notebooks-list.jsx'; import NotebookRenderer from './notebook-renderer.jsx'; import SplitPane from 'react-split-pane'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import Spinner from '../utils/spinner.jsx'; import { withRouter } from "react-router-dom"; @@ -16,6 +17,12 @@ const PAGE_SIZE = 100; class Notebooks extends React.Component { + static propTypes = { + // React router props. + match: PropTypes.object, + history: PropTypes.object, + }; + state = { notebooks: [], selected_notebook: {}, @@ -26,7 +33,7 @@ class Notebooks extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.fetchNotebooks, POLL_TIME); this.fetchNotebooks(); } @@ -39,7 +46,7 @@ class Notebooks extends React.Component { fetchNotebooks = () => { // Cancel any in flight calls. this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.get("v1/GetNotebooks", { count: PAGE_SIZE, diff --git a/gui/velociraptor/src/components/notebooks/notebooks-list.jsx b/gui/velociraptor/src/components/notebooks/notebooks-list.jsx index a4ace8716b8..37457dbc46f 100644 --- a/gui/velociraptor/src/components/notebooks/notebooks-list.jsx +++ b/gui/velociraptor/src/components/notebooks/notebooks-list.jsx @@ -21,7 +21,7 @@ import Alert from 'react-bootstrap/Alert'; import UserForm from '../utils/users.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import { formatColumns } from "../core/table.jsx"; import { withRouter } from "react-router-dom"; @@ -36,7 +36,7 @@ class NewNotebook extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); if(!_.isEmpty(this.props.notebook)) { this.setState({ name: this.props.notebook.name, @@ -165,7 +165,7 @@ class DeleteNotebook extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -217,6 +217,9 @@ class NotebooksList extends React.Component { selected_notebook: PropTypes.object, setSelectedNotebook: PropTypes.func.isRequired, fetchNotebooks: PropTypes.func.isRequired, + + // React router props. + history: PropTypes.object, }; state = { @@ -328,7 +331,7 @@ class NotebooksList extends React.Component { onClick={this.setFullScreen} variant="default"> - {T("Full Screen")} + {T("Full Screen")} diff --git a/gui/velociraptor/src/components/notebooks/timelines.jsx b/gui/velociraptor/src/components/notebooks/timelines.jsx index 2116c1d4003..e904ff60989 100644 --- a/gui/velociraptor/src/components/notebooks/timelines.jsx +++ b/gui/velociraptor/src/components/notebooks/timelines.jsx @@ -3,7 +3,7 @@ import "./timelines.css"; import React from 'react'; import PropTypes from 'prop-types'; import _ from 'lodash'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; import parse from 'html-react-parser'; @@ -102,7 +102,7 @@ export class AddVQLCellToTimeline extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.getTables(); } diff --git a/gui/velociraptor/src/components/server/server-info.jsx b/gui/velociraptor/src/components/server/server-info.jsx index 40b26fcd98d..b80b384da07 100644 --- a/gui/velociraptor/src/components/server/server-info.jsx +++ b/gui/velociraptor/src/components/server/server-info.jsx @@ -1,11 +1,9 @@ import React, { Component } from 'react'; - -import _ from 'lodash'; +import PropTypes from 'prop-types'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { withRouter, Link } from "react-router-dom"; import ShellViewer from "../clients/shell-viewer.jsx"; -import VeloForm from '../forms/form.jsx'; import MetadataEditor from "../clients/metadata.jsx"; import ToggleButtonGroup from 'react-bootstrap/ToggleButtonGroup'; @@ -13,15 +11,15 @@ import ToggleButton from 'react-bootstrap/ToggleButton'; import CardDeck from 'react-bootstrap/CardDeck'; import Card from 'react-bootstrap/Card'; -import api from '../core/api-service.jsx'; -import axios from 'axios'; -import { parseCSV } from '../utils/csv.jsx'; +import {CancelToken} from 'axios'; import "../clients/host-info.css"; -const POLL_TIME = 5000; - class ServerInfo extends Component { - static propTypes = {} + static propTypes = { + // React router props. + match: PropTypes.object, + history: PropTypes.object, + } state = { // The mode of the host info tab set. @@ -31,7 +29,7 @@ class ServerInfo extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/sidebar/hotkeys.jsx b/gui/velociraptor/src/components/sidebar/hotkeys.jsx index 0c9880124ee..d063e992547 100644 --- a/gui/velociraptor/src/components/sidebar/hotkeys.jsx +++ b/gui/velociraptor/src/components/sidebar/hotkeys.jsx @@ -8,6 +8,9 @@ import { withRouter } from "react-router-dom"; class SidebarKeyNavigator extends React.Component { static propTypes = { client: PropTypes.object, + + // React router props. + history: PropTypes.object, } render() { diff --git a/gui/velociraptor/src/components/sidebar/navigator.jsx b/gui/velociraptor/src/components/sidebar/navigator.jsx index 34413c518d0..d76ba2bde08 100644 --- a/gui/velociraptor/src/components/sidebar/navigator.jsx +++ b/gui/velociraptor/src/components/sidebar/navigator.jsx @@ -98,7 +98,7 @@ class VeloNavigator extends Component { {T("Main Menu")}
    -
  • +
  • @@ -109,7 +109,7 @@ class VeloNavigator extends Component {
  • -
  • +
  • @@ -120,7 +120,7 @@ class VeloNavigator extends Component {
  • -
  • +
  • @@ -132,7 +132,7 @@ class VeloNavigator extends Component {
  • {!customization.disable_server_events && ( -
  • +
  • @@ -144,7 +144,7 @@ class VeloNavigator extends Component {
  • )} -
  • +
  • @@ -155,7 +155,7 @@ class VeloNavigator extends Component {
  • -
  • +
  • @@ -167,7 +167,7 @@ class VeloNavigator extends Component {
  • {user_is_admin && !customization.disable_user_management && ( -
  • +
  • diff --git a/gui/velociraptor/src/components/sidebar/user-dashboard.jsx b/gui/velociraptor/src/components/sidebar/user-dashboard.jsx index 5176e0b54b6..195ba5aabe0 100644 --- a/gui/velociraptor/src/components/sidebar/user-dashboard.jsx +++ b/gui/velociraptor/src/components/sidebar/user-dashboard.jsx @@ -1,4 +1,5 @@ import "./user-dashboard.css"; +import PropTypes from 'prop-types'; import React from 'react'; @@ -23,7 +24,8 @@ const ranges = [ class UserDashboard extends React.Component { static propTypes = { - + // React router props. + history: PropTypes.object, }; constructor(props) { diff --git a/gui/velociraptor/src/components/timeline/timeline.jsx b/gui/velociraptor/src/components/timeline/timeline.jsx index 1430a5a14f2..fc1719312c5 100644 --- a/gui/velociraptor/src/components/timeline/timeline.jsx +++ b/gui/velociraptor/src/components/timeline/timeline.jsx @@ -8,7 +8,7 @@ import Timeline, { CustomMarker, } from 'react-calendar-timeline'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import { PrepareData } from '../core/table.jsx'; import VeloTimestamp from "../utils/time.jsx"; import VeloValueRenderer from '../utils/value.jsx'; @@ -137,7 +137,7 @@ export default class TimelineRenderer extends React.Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchRows(); } @@ -205,10 +205,10 @@ export default class TimelineRenderer extends React.Component { notebook_id: this.props.notebook_id, }; - let url = this.props.url || "v1/GetTable"; + let url = "v1/GetTable"; this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); diff --git a/gui/velociraptor/src/components/tools/tool-viewer.jsx b/gui/velociraptor/src/components/tools/tool-viewer.jsx index 4f35a902a3f..17b606e7043 100644 --- a/gui/velociraptor/src/components/tools/tool-viewer.jsx +++ b/gui/velociraptor/src/components/tools/tool-viewer.jsx @@ -3,7 +3,7 @@ import './tool-viewer.css'; import _ from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import Modal from 'react-bootstrap/Modal'; import Button from 'react-bootstrap/Button'; import api from '../core/api-service.jsx'; @@ -25,7 +25,7 @@ class ResetToolDialog extends React.Component { }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -75,7 +75,7 @@ export default class ToolViewer extends React.Component { }; componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.fetchToolInfo(); } diff --git a/gui/velociraptor/src/components/users/add_orgs.jsx b/gui/velociraptor/src/components/users/add_orgs.jsx index a9816d60a48..65bea61efdd 100644 --- a/gui/velociraptor/src/components/users/add_orgs.jsx +++ b/gui/velociraptor/src/components/users/add_orgs.jsx @@ -7,7 +7,7 @@ import T from '../i8n/i8n.jsx'; import UserConfig from '../core/user.jsx'; import OrgSelector from '../hunts/orgs.jsx'; import Button from 'react-bootstrap/Button'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import api from '../core/api-service.jsx'; @@ -42,7 +42,7 @@ export default class AddOrgDialog extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -51,7 +51,7 @@ export default class AddOrgDialog extends Component { addUserToOrg = () => { this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); let name = this.props.user_name; if(!name) return; diff --git a/gui/velociraptor/src/components/users/add_user.jsx b/gui/velociraptor/src/components/users/add_user.jsx index 49a3642871c..8d2d4fe81cf 100644 --- a/gui/velociraptor/src/components/users/add_user.jsx +++ b/gui/velociraptor/src/components/users/add_user.jsx @@ -7,7 +7,7 @@ import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import Row from 'react-bootstrap/Row'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; export default class AddUserDialog extends Component { static propTypes = { @@ -21,7 +21,7 @@ export default class AddUserDialog extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -31,7 +31,7 @@ export default class AddUserDialog extends Component { addUser = ()=>{ this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); api.post("v1/CreateUser", { name: this.state.username, @@ -61,7 +61,7 @@ export default class AddUserDialog extends Component { rows={1} onChange={e=>this.setState({ username: e.currentTarget.value})} - value={this.props.value} /> + value={this.state.username} /> diff --git a/gui/velociraptor/src/components/users/edit-user.jsx b/gui/velociraptor/src/components/users/edit-user.jsx index f910c7dbbb7..5410727d854 100644 --- a/gui/velociraptor/src/components/users/edit-user.jsx +++ b/gui/velociraptor/src/components/users/edit-user.jsx @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import Modal from 'react-bootstrap/Modal'; import T from '../i8n/i8n.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import { PasswordChange } from './user-label.jsx'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -20,7 +20,7 @@ export default class EditUserDialog extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/users/user-inspector.jsx b/gui/velociraptor/src/components/users/user-inspector.jsx index c95f5dad426..5dceea50475 100644 --- a/gui/velociraptor/src/components/users/user-inspector.jsx +++ b/gui/velociraptor/src/components/users/user-inspector.jsx @@ -23,7 +23,7 @@ import AddUserDialog from './add_user.jsx'; import EditUserDialog from './edit-user.jsx'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; const POLL_TIME = 5000; @@ -297,8 +297,8 @@ class UsersOverview extends Component { } componentDidMount = () => { - this.setACLsource = axios.CancelToken.source(); - this.getACLsource = axios.CancelToken.source(); + this.setACLsource = CancelToken.source(); + this.getACLsource = CancelToken.source(); } componentWillUnmount() { @@ -308,7 +308,7 @@ class UsersOverview extends Component { setACL = (acl) => { this.setACLsource.cancel(); - this.setACLsource = axios.CancelToken.source(); + this.setACLsource = CancelToken.source(); api.post("v1/SetUserRoles", acl, this.setACLsource.token).then(response=>{ @@ -322,7 +322,7 @@ class UsersOverview extends Component { getACL = (user_name, org) => { this.getACLsource.cancel(); - this.getACLsource = axios.CancelToken.source(); + this.getACLsource = CancelToken.source(); this.setState({acl: {}}); let org_id = org && org.id; @@ -598,6 +598,10 @@ class OrgsOverview extends UsersOverview { class UserInspector extends Component { static contextType = UserConfig; + static propTypes = { + history: PropTypes.object, + } + state = { tab: "users", users_initialized: false, @@ -605,7 +609,7 @@ class UserInspector extends Component { } componentDidMount = () => { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.interval = setInterval(this.loadUsers, POLL_TIME); this.loadUsers(); } @@ -628,7 +632,7 @@ class UserInspector extends Component { loadUsers = () => { this.source.cancel(); - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); this.setState({loading: true}); diff --git a/gui/velociraptor/src/components/users/user-label.jsx b/gui/velociraptor/src/components/users/user-label.jsx index 32c7c950d20..5ccdcd0164b 100644 --- a/gui/velociraptor/src/components/users/user-label.jsx +++ b/gui/velociraptor/src/components/users/user-label.jsx @@ -19,7 +19,7 @@ import Form from 'react-bootstrap/Form'; import Col from 'react-bootstrap/Col'; import Row from 'react-bootstrap/Row'; import api from '../core/api-service.jsx'; -import axios from 'axios'; +import {CancelToken} from 'axios'; import VeloForm from '../forms/form.jsx'; import T from '../i8n/i8n.jsx'; import OverlayTrigger from 'react-bootstrap/OverlayTrigger'; @@ -35,7 +35,7 @@ class _PasswordChange extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { @@ -90,6 +90,9 @@ class _PasswordChangeForm extends React.PureComponent { static propTypes = { username: PropTypes.string, onClose: PropTypes.func.isRequired, + + // React router props. + history: PropTypes.object, } render() { @@ -361,7 +364,7 @@ export default class UserLabel extends React.Component { } componentDidMount() { - this.source = axios.CancelToken.source(); + this.source = CancelToken.source(); } componentWillUnmount() { diff --git a/gui/velociraptor/src/components/utils/hex.css b/gui/velociraptor/src/components/utils/hex.css index b184b7e1a5c..5b1e35ba180 100644 --- a/gui/velociraptor/src/components/utils/hex.css +++ b/gui/velociraptor/src/components/utils/hex.css @@ -7,6 +7,15 @@ white-space: nowrap; } +.textdump { + font-family: var(--font-monospace); + font-size: 13px; + color: var(--color-monospace-color); + padding: 0; + margin: 0; + white-space: pre; +} + .hexdump { margin: 0px; } diff --git a/gui/velociraptor/src/components/utils/hex.jsx b/gui/velociraptor/src/components/utils/hex.jsx index 38d792afb29..eaf6ee6c802 100644 --- a/gui/velociraptor/src/components/utils/hex.jsx +++ b/gui/velociraptor/src/components/utils/hex.jsx @@ -7,7 +7,6 @@ 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 { @@ -199,7 +198,7 @@ export default class HexView extends React.Component { // Pad with extra spaces to maintain alignment if(data_row.length < columns) { let pad = columns - data_row.length % columns; - for (var j = 0; j < pad; j++) { + for (let j = 0; j < pad; j++) { data_row.push({v:" ", p:true, safe:" "}); } } @@ -344,7 +343,7 @@ export default class HexView extends React.Component { { more && (this.state.expanded ? - +