From c233dc690187d376b4f5440321702c0a3b24533f Mon Sep 17 00:00:00 2001 From: Mike Cohen Date: Fri, 6 Aug 2021 22:53:45 +1000 Subject: [PATCH] Refactor of data store and filestore APIs (#1177) --- Makefile | 5 +- actions/proto/vql.pb.go | 386 +++--- actions/proto/vql.proto | 1 - api/api.go | 19 +- api/clients.go | 18 +- api/csv.go | 26 +- api/download.go | 153 +-- api/events.go | 9 +- api/mock/api_mock.go | 30 +- api/notebooks.go | 127 +- api/proto/api.pb.go | 1120 +++++++++-------- api/proto/api.pb.gw.go | 119 +- api/proto/api.proto | 19 +- api/proto/api_grpc.pb.go | 76 +- api/proto/users.pb.go | 531 +++++--- api/proto/users.proto | 14 + api/proto/vfs_api.pb.go | 549 ++++++++ api/proto/vfs_api.proto | 47 + api/proxy.go | 10 +- api/server_monitoring.go | 6 +- api/users.go | 9 + api/vfs.go | 160 +-- artifacts/definitions/Demo/Plugins/GUI.yaml | 17 +- .../Server/Internal/Inventory.yaml | 5 + .../Server/Utils/SaveFavoriteFlow.yaml | 35 + artifacts/proto/artifact.pb.go | 717 ++++++----- artifacts/proto/artifact.proto | 7 + artifacts/testdata/windows/test.config.yaml | 4 +- bin/collector_test.go | 8 +- bin/debian.go | 8 +- bin/fs.go | 4 +- bin/golden.go | 18 +- config/config.go | 4 +- config/migration.go | 20 + constants/constants.go | 20 - crypto/server/manager.go | 4 +- datastore/datastore.go | 43 +- datastore/datastore_test.go | 170 ++- datastore/filebased.go | 343 ++--- datastore/filebased_benchmark_test.go | 2 +- datastore/filebased_json.go | 97 ++ datastore/filebased_test.go | 59 +- datastore/memory.go | 249 ++-- datastore/paths.go | 1 + file_store/{api => accessors}/accessor.go | 82 +- file_store/{api => accessors}/fs.go | 32 +- file_store/api/adapter.go | 34 +- file_store/api/extensions.go | 104 ++ file_store/api/file_store.go | 25 +- file_store/api/paths.go | 146 +++ file_store/api/queues.go | 4 +- file_store/api/uploader.go | 11 +- file_store/directory/csv.go | 2 +- file_store/directory/directory.go | 154 +-- file_store/directory/directory_components.go | 108 ++ file_store/directory/directory_test.go | 4 +- file_store/directory/json.go | 2 +- file_store/directory/queue_test.go | 8 +- file_store/directory/result_sets.go | 19 +- file_store/file_store.go | 9 +- file_store/memory/memory.go | 126 +- file_store/memory/memory_component.go | 131 ++ file_store/memory/queue.go | 3 +- file_store/memory/queue_test.go | 7 +- file_store/path_specs/fs_path_spec.go | 89 ++ file_store/path_specs/path_specs.go | 162 +++ file_store/path_specs/utils.go | 26 + file_store/test_utils/testing.go | 6 +- file_store/{api => tests}/testsuite.go | 149 ++- file_store/utils.go | 4 +- flows/api.go | 21 +- flows/artifacts.go | 21 +- flows/artifacts_test.go | 30 +- flows/hunts.go | 2 +- flows/hunts_test.go | 2 +- flows/proto/artifact_collector.pb.go | 234 ++-- flows/proto/artifact_collector.proto | 1 + flows/proto/vfs.pb.go | 560 +-------- flows/proto/vfs.proto | 61 +- .../src/components/clients/client-summary.js | 2 +- .../src/components/clients/host-info.js | 12 +- .../src/components/flows/flows-list.js | 109 +- .../src/components/flows/new-collection.css | 9 + .../src/components/flows/new-collection.js | 41 +- .../src/components/flows/utils.js | 6 +- .../notebooks/notebook-cell-renderer.js | 19 +- .../components/notebooks/notebook-delete.js | 12 +- .../src/components/notebooks/timelines.js | 11 +- .../src/components/timeline/timeline.js | 3 +- .../src/components/vfs/file-hex-view.js | 12 +- .../src/components/vfs/file-list.js | 4 +- .../src/components/vfs/file-text-view.js | 13 +- .../src/components/vfs/file-tree.js | 2 +- gui/velociraptor/src/index.js | 4 +- http_comms/comms_test.go | 26 +- http_comms/e2e_test.go | 2 +- paths/artifacts.go | 11 +- paths/artifacts/logs.go | 72 +- paths/artifacts/paths.go | 120 +- paths/artifacts/paths_test.go | 21 +- paths/artifacts_test.go | 14 + paths/client.go | 93 +- paths/client_test.go | 65 + paths/constants.go | 70 ++ paths/doc.go | 18 + paths/flow_metadata.go | 151 +-- paths/flow_metadata_test.go | 33 + paths/hunt_metadata.go | 56 +- paths/hunt_metadata_test.go | 26 + paths/inventory.go | 18 +- paths/notebooks.go | 204 +++ paths/notebooks_test.go | 40 + paths/ntfs.go | 52 + paths/ntfs_test.go | 31 + paths/paths_test.go | 112 ++ paths/server.go | 6 +- paths/timelines.go | 66 + paths/timelines_test.go | 25 + paths/users.go | 62 +- paths/users_test.go | 25 + reporting/acls.go | 10 +- reporting/container.go | 3 +- reporting/gui.go | 107 +- reporting/notebooks.go | 18 +- reporting/paths.go | 201 --- reporting/report.go | 3 +- result_sets/registration.go | 13 +- result_sets/simple/simple.go | 42 +- result_sets/simple/simple_test.go | 5 +- .../TestTimedResultSetMigration.golden | 12 +- .../fixtures/TestTimedResultSetWriting.golden | 12 +- result_sets/timed/reader.go | 37 +- result_sets/timed/reader_test.go | 3 +- result_sets/timed/writer.go | 31 +- search/clients.go | 4 +- search/mru.go | 22 + search/search.go | 8 +- server/comms.go | 9 +- server/server.go | 2 +- server/server_test.go | 27 +- .../client_monitoring/client_monitoring.go | 5 +- services/hunt_dispatcher/hunt_dispatcher.go | 5 +- services/hunt_manager/hunt_manager.go | 4 +- services/hunt_manager/hunt_manager_test.go | 11 +- services/interrogation/interrogation.go | 6 +- services/interrogation/interrogation_test.go | 7 +- services/inventory/inventory.go | 12 +- services/journal/journal.go | 17 + services/labels/labels.go | 10 +- services/labels/labels_test.go | 3 +- services/launcher/launcher.go | 2 +- services/repository/filestore.go | 59 +- services/repository/repository_test.go | 58 + services/sanity/sanity_test.go | 6 +- services/server_artifacts/server_artifacts.go | 10 +- .../server_artifacts/server_artifacts_test.go | 4 +- services/server_artifacts/server_uploader.go | 13 +- .../fixtures/TestMultipleArtifacts.golden | 2 +- services/server_monitoring/logger.go | 10 +- .../server_monitoring/server_monitoring.go | 6 +- .../server_monitoring_test.go | 6 +- services/vfs_service/vfs_service.go | 82 +- services/vfs_service/vfs_service_test.go | 20 +- timelines/paths.go | 47 - timelines/proto/timelines.pb.go | 36 +- timelines/proto/timelines.proto | 2 - timelines/reader.go | 6 +- timelines/supertimeline.go | 7 +- timelines/timelines_test.go | 11 +- timelines/writer.go | 3 +- uploads/file_based.go | 3 +- users/favorites.go | 37 + users/notifications.go | 6 +- users/users.go | 6 +- utils/copy.go | 6 + utils/fixtures/TestSanitize.golden | 10 + utils/path.go | 70 +- utils/sanitize.go | 113 ++ utils/sanitize_test.go | 35 + vql/{common => filesystem}/copy.go | 11 +- vql/filesystem/rm.go | 57 + vql/networking/http_client.go | 2 +- vql/parsers/csv/csv.go | 33 - vql/parsers/sqlite_windows.go | 7 + vql/server/clients/clients.go | 4 +- vql/server/compress.go | 77 +- vql/server/delete.go | 11 +- vql/server/downloads/downloads.go | 93 +- vql/server/downloads/reporting.go | 20 +- vql/server/event_monitoring.go | 4 +- vql/server/favorites/create.go | 108 ++ vql/server/file_store.go | 22 +- vql/server/flows.go | 16 +- vql/server/hunts/hunts.go | 16 +- vql/server/monitoring.go | 10 +- vql/server/notebooks/delete.go | 11 +- vql/server/parallel_test.go | 6 +- vql/server/results.go | 11 +- vql/server/search.go | 4 +- vql/server/timelines/create.go | 6 +- vql/server/timelines/reader.go | 8 +- vql/tools/import.go | 6 +- vql_plugins/server.go | 1 + vtesting/file_info.go | 11 +- 204 files changed, 6994 insertions(+), 4212 deletions(-) create mode 100644 api/proto/vfs_api.pb.go create mode 100644 api/proto/vfs_api.proto create mode 100644 artifacts/definitions/Server/Internal/Inventory.yaml create mode 100644 artifacts/definitions/Server/Utils/SaveFavoriteFlow.yaml create mode 100644 datastore/filebased_json.go create mode 100644 datastore/paths.go rename file_store/{api => accessors}/accessor.go (62%) rename file_store/{api => accessors}/fs.go (57%) create mode 100644 file_store/api/extensions.go create mode 100644 file_store/api/paths.go create mode 100644 file_store/directory/directory_components.go create mode 100644 file_store/memory/memory_component.go create mode 100644 file_store/path_specs/fs_path_spec.go create mode 100644 file_store/path_specs/path_specs.go create mode 100644 file_store/path_specs/utils.go rename file_store/{api => tests}/testsuite.go (60%) create mode 100644 paths/artifacts_test.go create mode 100644 paths/client_test.go create mode 100644 paths/constants.go create mode 100644 paths/flow_metadata_test.go create mode 100644 paths/hunt_metadata_test.go create mode 100644 paths/notebooks.go create mode 100644 paths/notebooks_test.go create mode 100644 paths/ntfs_test.go create mode 100644 paths/paths_test.go create mode 100644 paths/timelines.go create mode 100644 paths/timelines_test.go create mode 100644 paths/users_test.go delete mode 100644 reporting/paths.go create mode 100644 search/mru.go create mode 100644 services/repository/repository_test.go delete mode 100644 timelines/paths.go create mode 100644 users/favorites.go create mode 100644 utils/fixtures/TestSanitize.golden create mode 100644 utils/sanitize.go create mode 100644 utils/sanitize_test.go rename vql/{common => filesystem}/copy.go (92%) create mode 100644 vql/filesystem/rm.go create mode 100644 vql/parsers/sqlite_windows.go create mode 100644 vql/server/favorites/create.go diff --git a/Makefile b/Makefile index 1bc97d1b44c..5896f8bf8eb 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ test: go test -v --tags server_vql ./... golden: - ./output/velociraptor -v --config artifacts/testdata/windows/test.config.yaml golden artifacts/testdata/server/testcases/ --env srcDir=`pwd` --filter= + ./output/velociraptor -v --config artifacts/testdata/windows/test.config.yaml golden artifacts/testdata/server/testcases/ --env srcDir=`pwd` --filter=${GOLDEN} references: ./output/velociraptor vql export docs/references/vql.yaml > docs/references/vql.yaml.tmp @@ -57,5 +57,8 @@ debug: debug_client: dlv debug --build-flags="-tags 'server_vql extras'" ./bin/ -- client -v +debug_golden: + dlv debug --build-flags="-tags 'server_vql extras'" ./bin/ -- --config artifacts/testdata/windows/test.config.yaml golden artifacts/testdata/server/testcases/ --env srcDir=`pwd` --disable_alarm --filter=${GOLDEN} + lint: golangci-lint run diff --git a/actions/proto/vql.pb.go b/actions/proto/vql.pb.go index 71bd52cd2db..9333621e235 100644 --- a/actions/proto/vql.pb.go +++ b/actions/proto/vql.pb.go @@ -701,200 +701,198 @@ var File_vql_proto protoreflect.FileDescriptor var file_vql_proto_rawDesc = []byte{ 0x0a, 0x09, 0x76, 0x71, 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, 0x1a, 0x19, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, - 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x02, 0x0a, 0x0a, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x12, 0x88, 0x01, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x74, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x6e, 0x12, 0x6c, 0x54, 0x68, 0x65, 0x20, 0x6e, - 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, - 0x65, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x76, 0x65, 0x20, 0x74, 0x6f, - 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, - 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x69, 0x74, - 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x72, 0x65, 0x74, - 0x72, 0x69, 0x65, 0x76, 0x65, 0x73, 0x2e, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x4c, 0x0a, - 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x2a, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x24, 0x12, 0x22, 0x57, 0x68, 0x61, 0x74, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x69, 0x73, 0x20, 0x73, - 0x75, 0x70, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x6f, 0x2e, 0x52, 0x0b, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x03, 0x56, - 0x51, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x29, - 0x12, 0x27, 0x54, 0x68, 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, - 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x03, 0x56, 0x51, 0x4c, 0x22, 0x30, - 0x0a, 0x06, 0x56, 0x51, 0x4c, 0x45, 0x6e, 0x76, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x22, 0xe8, 0x08, 0x0a, 0x10, 0x56, 0x51, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x41, 0x72, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x65, - 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x69, - 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, - 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x5c, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, - 0x45, 0x6e, 0x76, 0x42, 0x3b, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x35, 0x12, 0x33, 0x45, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x5a, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x31, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2b, 0x12, - 0x29, 0x54, 0x68, 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x05, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x12, 0x9d, 0x01, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x77, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x04, 0x42, 0x83, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x7d, 0x12, 0x62, 0x54, 0x68, - 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x20, 0x70, - 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x20, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x20, 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, - 0x61, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, - 0x73, 0x70, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x20, 0x6d, 0x75, 0x6c, - 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x2e, - 0x22, 0x11, 0x4d, 0x61, 0x78, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x70, - 0x61, 0x72, 0x74, 0x32, 0x04, 0x31, 0x30, 0x30, 0x30, 0x52, 0x06, 0x6d, 0x61, 0x78, 0x52, 0x6f, - 0x77, 0x12, 0xcb, 0x01, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x77, 0x61, 0x69, 0x74, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x04, 0x42, 0xaf, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0xa8, 0x01, 0x12, 0x7d, - 0x46, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, - 0x20, 0x77, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, - 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, 0x61, 0x66, 0x74, 0x65, 0x72, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, - 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, - 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x65, 0x72, 0x73, - 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x6e, 0x65, 0x76, 0x65, 0x72, 0x20, 0x72, 0x65, 0x61, - 0x6c, 0x6c, 0x79, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x2e, 0x22, 0x23, 0x42, - 0x61, 0x74, 0x63, 0x68, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x20, 0x74, 0x68, - 0x61, 0x74, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x6f, 0x6e, - 0x67, 0x2e, 0x32, 0x02, 0x31, 0x30, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x57, 0x61, 0x69, 0x74, 0x12, - 0xc8, 0x01, 0x0a, 0x0e, 0x6f, 0x70, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, - 0x6e, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x02, 0x42, 0xa1, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, - 0x9a, 0x01, 0x12, 0x97, 0x01, 0x41, 0x6e, 0x20, 0x4f, 0x70, 0x20, 0x69, 0x73, 0x20, 0x64, 0x65, - 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x61, 0x72, - 0x62, 0x69, 0x74, 0x72, 0x61, 0x72, 0x79, 0x20, 0x75, 0x6e, 0x69, 0x74, 0x20, 0x6f, 0x66, 0x20, - 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x73, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x6c, 0x69, 0x6d, - 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x79, 0x70, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x20, - 0x56, 0x51, 0x4c, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, - 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x70, 0x73, 0x20, 0x74, 0x6f, 0x77, 0x61, 0x72, - 0x64, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x61, 0x73, 0x20, - 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x0c, 0x6f, 0x70, - 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x6e, 0x0a, 0x09, 0x61, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x42, 0x3f, - 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x39, 0x12, 0x37, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x68, 0x65, 0x6c, 0x70, 0x20, 0x77, - 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, - 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x42, 0x2a, 0xe2, 0xfc, 0xe3, - 0xc4, 0x01, 0x24, 0x12, 0x22, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x74, 0x69, 0x6d, - 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, - 0x74, 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x2e, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x18, 0x1b, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x4b, - 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x09, 0x42, 0x35, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2d, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x20, 0x77, 0x65, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x6e, - 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, - 0x56, 0x51, 0x4c, 0x2e, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x22, 0x38, 0x0a, 0x0a, 0x56, - 0x51, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x61, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x6c, - 0x75, 0x6d, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xa0, 0x06, 0x0a, 0x0b, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x18, 0x12, - 0x16, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x72, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x4a, 0x53, 0x4f, 0x4e, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x18, - 0x12, 0x16, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x72, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x0d, 0x4a, 0x53, 0x4f, 0x4e, 0x4c, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x07, 0x43, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x38, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x32, - 0x12, 0x30, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x6f, 0x6c, 0x75, - 0x6d, 0x6e, 0x20, 0x68, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x64, - 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x2e, 0x52, 0x07, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x5e, 0x0a, 0x05, 0x74, - 0x79, 0x70, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x61, 0x70, 0x42, 0x35, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2d, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x62, - 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x20, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x2e, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x52, 0x0a, 0x08, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x37, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x31, 0x12, 0x2f, 0x43, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x6c, 0x6f, 0x67, - 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x77, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x2e, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x79, 0x49, 0x64, 0x12, - 0x74, 0x0a, 0x04, 0x70, 0x61, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x42, 0x60, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x5a, 0x12, 0x58, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x20, 0x56, 0x51, 0x4c, - 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, - 0x70, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x79, - 0x20, 0x70, 0x61, 0x72, 0x74, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x63, 0x61, 0x72, - 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, - 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, - 0x04, 0x70, 0x61, 0x72, 0x74, 0x12, 0x4d, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x24, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1e, 0x12, - 0x1c, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, - 0x77, 0x61, 0x73, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x05, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x5c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x3e, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x38, 0x0a, - 0x0b, 0x52, 0x44, 0x46, 0x44, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x29, 0x54, 0x68, - 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x77, 0x61, 0x73, 0x20, 0x67, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x52, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x77, 0x73, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x42, 0x33, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2d, 0x12, 0x2b, - 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x20, 0x6f, 0x66, 0x20, - 0x72, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x2e, 0x52, 0x09, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x22, 0x45, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, - 0x12, 0x3d, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x21, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1b, 0x12, 0x19, 0x54, 0x68, 0x65, 0x20, - 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, - 0xaa, 0x01, 0x0a, 0x0d, 0x56, 0x51, 0x4c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, - 0x65, 0x12, 0x55, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, - 0x20, 0x12, 0x1e, 0x41, 0x20, 0x73, 0x65, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x76, 0x65, 0x6e, - 0x74, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x75, 0x6e, - 0x2e, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x28, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, - 0x22, 0x12, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x6f, - 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x2e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xfb, 0x02, 0x0a, - 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x64, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, - 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1d, - 0x0a, 0x0a, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x70, 0x69, 0x6e, - 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x12, 0x37, 0x0a, 0x18, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, - 0x6f, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x6f, - 0x67, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x42, 0x35, 0x5a, 0x33, 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, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x02, 0x0a, 0x0a, 0x56, 0x51, 0x4c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x88, 0x01, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x74, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x6e, 0x12, 0x6c, + 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, + 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x68, 0x6f, + 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x76, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x64, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x77, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x69, 0x6e, 0x66, 0x6f, + 0x72, 0x6d, 0x61, 0x69, 0x74, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x73, 0x2e, 0x52, 0x04, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x4c, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2a, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x24, 0x12, + 0x22, 0x57, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x20, 0x69, 0x73, 0x20, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x64, 0x6f, 0x2e, 0x52, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x41, 0x0a, 0x03, 0x56, 0x51, 0x4c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x29, 0x12, 0x27, 0x54, 0x68, 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x20, + 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x03, + 0x56, 0x51, 0x4c, 0x22, 0x30, 0x0a, 0x06, 0x56, 0x51, 0x4c, 0x45, 0x6e, 0x76, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xe8, 0x08, 0x0a, 0x10, 0x56, 0x51, 0x4c, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x12, 0x22, 0x0a, 0x0c, 0x70, 0x72, + 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, + 0x0a, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x18, 0x1c, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61, 0x6c, 0x12, 0x5c, 0x0a, 0x03, + 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x45, 0x6e, 0x76, 0x42, 0x3b, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x35, + 0x12, 0x33, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x5a, 0x0a, 0x05, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x31, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x2b, 0x12, 0x29, 0x54, 0x68, 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, + 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, + 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x9d, 0x01, 0x0a, 0x07, 0x6d, 0x61, 0x78, 0x5f, 0x72, + 0x6f, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x83, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, + 0x7d, 0x12, 0x62, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, 0x72, + 0x6f, 0x77, 0x73, 0x20, 0x70, 0x65, 0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x20, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x20, 0x6c, 0x61, 0x72, 0x67, + 0x65, 0x72, 0x20, 0x74, 0x68, 0x61, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, + 0x6c, 0x20, 0x62, 0x65, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x63, 0x72, 0x6f, 0x73, + 0x73, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x73, 0x2e, 0x22, 0x11, 0x4d, 0x61, 0x78, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x20, + 0x70, 0x65, 0x72, 0x20, 0x70, 0x61, 0x72, 0x74, 0x32, 0x04, 0x31, 0x30, 0x30, 0x30, 0x52, 0x06, + 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, 0x12, 0xcb, 0x01, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x77, + 0x61, 0x69, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x42, 0xaf, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, + 0x01, 0xa8, 0x01, 0x12, 0x7d, 0x46, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x77, 0x65, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x20, + 0x61, 0x66, 0x74, 0x65, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2e, + 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, + 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x6c, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x65, 0x72, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x6e, 0x65, 0x76, 0x65, + 0x72, 0x20, 0x72, 0x65, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x2e, 0x22, 0x23, 0x42, 0x61, 0x74, 0x63, 0x68, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x2e, 0x32, 0x02, 0x31, 0x30, 0x52, 0x07, 0x6d, 0x61, 0x78, + 0x57, 0x61, 0x69, 0x74, 0x12, 0xc8, 0x01, 0x0a, 0x0e, 0x6f, 0x70, 0x73, 0x5f, 0x70, 0x65, 0x72, + 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x02, 0x42, 0xa1, 0x01, + 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x9a, 0x01, 0x12, 0x97, 0x01, 0x41, 0x6e, 0x20, 0x4f, 0x70, 0x20, + 0x69, 0x73, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x20, 0x61, 0x73, 0x20, 0x73, 0x6f, + 0x6d, 0x65, 0x20, 0x61, 0x72, 0x62, 0x69, 0x74, 0x72, 0x61, 0x72, 0x79, 0x20, 0x75, 0x6e, 0x69, + 0x74, 0x20, 0x6f, 0x66, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x77, 0x6f, 0x72, 0x6b, 0x20, 0x74, 0x6f, 0x20, 0x62, + 0x65, 0x20, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x79, 0x70, 0x69, 0x63, + 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x20, 0x6f, 0x70, 0x73, 0x20, + 0x74, 0x6f, 0x77, 0x61, 0x72, 0x64, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x20, 0x61, 0x73, 0x20, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, + 0x2e, 0x52, 0x0c, 0x6f, 0x70, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, + 0x6e, 0x0a, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x74, 0x42, 0x3f, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x39, 0x12, 0x37, 0x41, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x68, + 0x65, 0x6c, 0x70, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x2e, 0x52, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, + 0x44, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, + 0x42, 0x2a, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x24, 0x12, 0x22, 0x4d, 0x61, 0x78, 0x69, 0x6d, 0x75, + 0x6d, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, + 0x75, 0x65, 0x72, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x2e, 0x52, 0x07, 0x74, 0x69, + 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, + 0x61, 0x74, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, + 0x65, 0x61, 0x74, 0x12, 0x4b, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x1a, 0x20, 0x03, + 0x28, 0x09, 0x42, 0x35, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2d, 0x41, 0x20, 0x6c, 0x69, + 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x20, 0x77, 0x65, 0x20, 0x77, + 0x69, 0x6c, 0x6c, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x20, + 0x74, 0x68, 0x69, 0x73, 0x20, 0x56, 0x51, 0x4c, 0x2e, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, + 0x22, 0x38, 0x0a, 0x0a, 0x56, 0x51, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x61, 0x70, 0x12, 0x16, + 0x0a, 0x06, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xa0, 0x06, 0x0a, 0x0b, 0x56, + 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x18, 0x12, 0x16, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, + 0x65, 0x64, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x08, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x4a, 0x53, 0x4f, 0x4e, 0x4c, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x18, 0x12, 0x16, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x65, 0x6e, 0x63, 0x6f, + 0x64, 0x65, 0x64, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x0d, 0x4a, + 0x53, 0x4f, 0x4e, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x52, 0x0a, 0x07, + 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x38, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x32, 0x12, 0x30, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x20, 0x68, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x73, + 0x20, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x52, 0x07, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, + 0x12, 0x5e, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x4d, + 0x61, 0x70, 0x42, 0x35, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2d, 0x4d, 0x61, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6c, 0x75, + 0x6d, 0x6e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, + 0x69, 0x72, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, + 0x12, 0x52, 0x0a, 0x08, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x37, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x31, 0x12, 0x2f, 0x43, 0x68, 0x72, 0x6f, + 0x6e, 0x6f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x77, 0x65, 0x20, + 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x2e, 0x52, 0x07, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x49, 0x64, 0x12, 0x74, 0x0a, 0x04, 0x70, 0x61, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x04, 0x42, 0x60, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x5a, 0x12, 0x58, 0x4c, 0x61, 0x72, 0x67, + 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x20, + 0x61, 0x72, 0x65, 0x20, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x20, 0x61, 0x63, 0x72, 0x6f, 0x73, 0x73, + 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x70, 0x61, 0x72, 0x74, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x69, + 0x73, 0x20, 0x63, 0x61, 0x72, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, + 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x04, 0x70, 0x61, 0x72, 0x74, 0x12, 0x4d, 0x0a, 0x05, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x24, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x1e, 0x12, 0x1c, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x77, 0x61, 0x73, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, + 0x64, 0x2e, 0x52, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x5c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x3e, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x38, 0x0a, 0x0b, 0x52, 0x44, 0x46, 0x44, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x29, 0x54, 0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x77, 0x61, + 0x73, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x52, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x42, 0x33, 0xe2, 0xfc, 0xe3, + 0xc4, 0x01, 0x2d, 0x12, 0x2b, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x20, 0x6e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x2e, + 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x6c, + 0x6f, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x22, 0x45, 0x0a, + 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1b, 0x12, + 0x19, 0x54, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x0d, 0x56, 0x51, 0x4c, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x55, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, + 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x42, 0x26, + 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x41, 0x20, 0x73, 0x65, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, + 0x6f, 0x20, 0x72, 0x75, 0x6e, 0x2e, 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x42, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x28, + 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x22, 0x12, 0x20, 0x54, 0x68, 0x65, 0x20, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x20, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0xfb, 0x02, 0x0a, 0x0a, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, + 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x71, 0x64, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x71, 0x64, 0x6e, 0x12, 0x16, 0x0a, + 0x06, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, + 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x04, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, + 0x0b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x37, 0x0a, 0x18, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x72, 0x6f, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x66, 0x6c, 0x6f, 0x77, 0x5f, + 0x69, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x72, 0x6f, 0x67, 0x61, 0x74, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x42, + 0x35, 0x5a, 0x33, 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, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/actions/proto/vql.proto b/actions/proto/vql.proto index 9d63187a227..3ed9d3d3aa2 100644 --- a/actions/proto/vql.proto +++ b/actions/proto/vql.proto @@ -2,7 +2,6 @@ syntax = "proto3"; import "proto/semantic.proto"; -import "proto/flow_metadata.proto"; import "artifacts/proto/artifact.proto"; package proto; diff --git a/api/api.go b/api/api.go index e55c316d8a4..bc86710708c 100644 --- a/api/api.go +++ b/api/api.go @@ -54,6 +54,7 @@ import ( flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/grpc_client" "www.velocidex.com/golang/velociraptor/logging" + "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/search" "www.velocidex.com/golang/velociraptor/server" "www.velocidex.com/golang/velociraptor/services" @@ -406,7 +407,7 @@ func (self *ApiServer) SetGUIOptions( func (self *ApiServer) VFSListDirectory( ctx context.Context, - in *flows_proto.VFSListRequest) (*flows_proto.VFSListResponse, error) { + in *api_proto.VFSListRequest) (*api_proto.VFSListResponse, error) { defer Instrument("VFSListDirectory")() @@ -419,13 +420,13 @@ func (self *ApiServer) VFSListDirectory( } result, err := vfsListDirectory( - self.config, in.ClientId, in.VfsPath) + self.config, in.ClientId, in.VfsComponents) return result, err } func (self *ApiServer) VFSStatDirectory( ctx context.Context, - in *flows_proto.VFSListRequest) (*flows_proto.VFSListResponse, error) { + in *api_proto.VFSListRequest) (*api_proto.VFSListResponse, error) { defer Instrument("VFSStatDirectory")() @@ -438,13 +439,13 @@ func (self *ApiServer) VFSStatDirectory( } result, err := vfsStatDirectory( - self.config, in.ClientId, in.VfsPath) + self.config, in.ClientId, in.VfsComponents) return result, err } func (self *ApiServer) VFSStatDownload( ctx context.Context, - in *flows_proto.VFSStatDownloadRequest) (*flows_proto.VFSDownloadInfo, error) { + in *api_proto.VFSStatDownloadRequest) (*flows_proto.VFSDownloadInfo, error) { defer Instrument("VFSStatDownload")() @@ -457,7 +458,7 @@ func (self *ApiServer) VFSStatDownload( } result, err := vfsStatDownload( - self.config, in.ClientId, in.Accessor, in.Path) + self.config, in.ClientId, in.Accessor, in.Components) return result, err } @@ -477,7 +478,7 @@ func (self *ApiServer) VFSRefreshDirectory( } result, err := vfsRefreshDirectory( - self, ctx, in.ClientId, in.VfsPath, in.Depth) + self, ctx, in.ClientId, in.VfsComponents, in.Depth) return result, err } @@ -496,8 +497,10 @@ func (self *ApiServer) VFSGetBuffer( "User is not allowed to view the VFS.") } + path_spec := paths.NewClientPathManager( + in.ClientId).FSItem(in.Components) result, err := vfsGetBuffer( - self.config, in.ClientId, in.VfsPath, in.Offset, in.Length) + self.config, in.ClientId, path_spec, in.Offset, in.Length) return result, err } diff --git a/api/clients.go b/api/clients.go index 2266c946179..1ec2918853d 100644 --- a/api/clients.go +++ b/api/clients.go @@ -29,7 +29,6 @@ import ( "google.golang.org/grpc/status" "www.velocidex.com/golang/velociraptor/acls" api_proto "www.velocidex.com/golang/velociraptor/api/proto" - config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/datastore" "www.velocidex.com/golang/velociraptor/flows" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" @@ -104,7 +103,7 @@ func (self *ApiServer) GetClient( } if in.UpdateMru { - err = updateMRU(self.config, user_name, in.ClientId) + err = search.UpdateMRU(self.config, user_name, in.ClientId) if err != nil { return nil, err } @@ -167,18 +166,3 @@ func (self *ApiServer) GetClientFlows( return flows.GetFlows(self.config, in.ClientId, in.IncludeArchived, filter, in.Offset, in.Count) } - -func updateMRU( - config_obj *config_proto.Config, - user_name string, client_id string) error { - path_manager := &paths.UserPathManager{user_name} - db, err := datastore.GetDB(config_obj) - if err != nil { - return err - } - - err = db.SetIndex(config_obj, path_manager.MRU(), - client_id, []string{"mru"}) - - return err -} diff --git a/api/csv.go b/api/csv.go index 642baa6d669..62bc477442a 100644 --- a/api/csv.go +++ b/api/csv.go @@ -27,7 +27,6 @@ import ( "www.velocidex.com/golang/velociraptor/file_store/csv" "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/paths/artifacts" - "www.velocidex.com/golang/velociraptor/reporting" "www.velocidex.com/golang/velociraptor/result_sets" "www.velocidex.com/golang/velociraptor/timelines" @@ -47,14 +46,14 @@ func getTable( } result := &api_proto.GetTableResponse{} - path_manager, err := getPathManager(config_obj, in) + path_spec, err := getPathSpec(config_obj, in) if err != nil { return result, err } file_store_factory := file_store.GetFileStore(config_obj) rs_reader, err := result_sets.NewResultSetReader( - file_store_factory, path_manager) + file_store_factory, path_spec) if err != nil { return result, nil } @@ -103,17 +102,22 @@ func getTable( return result, nil } -func getPathManager( +func getPathSpec( config_obj *config_proto.Config, - in *api_proto.GetTableRequest) (api.PathManager, error) { + in *api_proto.GetTableRequest) (api.FSPathSpec, error) { if in.FlowId != "" && in.Artifact != "" { - return artifacts.NewArtifactPathManager( + path_manager, err := artifacts.NewArtifactPathManager( config_obj, in.ClientId, in.FlowId, in.Artifact) + if err != nil { + return nil, err + } + return path_manager.Path(), nil } else if in.FlowId != "" && in.Type != "" { flow_path_manager := paths.NewFlowPathManager( in.ClientId, in.FlowId) + switch in.Type { case "log": return flow_path_manager.Log(), nil @@ -127,8 +131,8 @@ func getPathManager( return paths.NewHuntPathManager(in.HuntId).ClientErrors(), nil } else if in.NotebookId != "" && in.CellId != "" { - return reporting.NewNotebookPathManager(in.NotebookId).Cell( - in.CellId).QueryStorage(in.TableId), nil + return paths.NewNotebookPathManager(in.NotebookId).Cell( + in.CellId).QueryStorage(in.TableId).Path(), nil } return nil, errors.New("Invalid request") @@ -225,8 +229,10 @@ func getTimeline( return nil, errors.New("NotebookId must be specified") } - path_manager := reporting.NewNotebookPathManager(in.NotebookId).Timeline(in.Timeline) - reader, err := timelines.NewSuperTimelineReader(config_obj, path_manager, in.SkipComponents) + path_manager := paths.NewNotebookPathManager(in.NotebookId). + SuperTimeline(in.Timeline) + reader, err := timelines.NewSuperTimelineReader( + config_obj, path_manager, in.SkipComponents) if err != nil { return nil, err } diff --git a/api/download.go b/api/download.go index cbf6269187c..d9e8477a1e6 100644 --- a/api/download.go +++ b/api/download.go @@ -26,14 +26,11 @@ package api import ( - "archive/zip" "io" "io/ioutil" "net/http" "net/url" "os" - "path" - "path/filepath" "strings" "sync" "time" @@ -48,7 +45,9 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/datastore" "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/file_store/api" "www.velocidex.com/golang/velociraptor/file_store/csv" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/flows" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/json" @@ -75,14 +74,17 @@ func returnError(w http.ResponseWriter, code int, message string) { } type vfsFileDownloadRequest struct { - ClientId string `schema:"client_id"` - VfsPath string `schema:"vfs_path,required"` - Offset int64 `schema:"offset"` - Length int `schema:"length"` - Encoding string `schema:"encoding"` + ClientId string `schema:"client_id"` + Components []string `schema:"components[],required"` + Offset int64 `schema:"offset"` + Length int `schema:"length"` + Encoding string `schema:"encoding"` } // URL format: /api/v1/DownloadVFSFile + +// This URL allows the caller to download **any** member of the +// filestore (providing they have at least read permissions). func vfsFileDownloadHandler( config_obj *config_proto.Config) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -94,7 +96,23 @@ func vfsFileDownloadHandler( return } - file, err := file_store.GetFileStore(config_obj).ReadFile(request.VfsPath) + db, _ := datastore.GetDB(config_obj) + + client_path_manager := paths.NewClientPathManager(request.ClientId) + info_path_spec := client_path_manager.VFSDownloadInfoPath( + request.Components) + download_info := &flows_proto.VFSDownloadInfo{} + + err = db.GetSubject(config_obj, info_path_spec, download_info) + if err != nil { + returnError(w, 404, err.Error()) + return + } + + path_spec := path_specs.NewUnsafeFilestorePath( + download_info.Components...). + SetType(api.PATH_TYPE_FILESTORE_ANY) + file, err := file_store.GetFileStore(config_obj).ReadFile(path_spec) if err != nil { returnError(w, 404, err.Error()) return @@ -108,7 +126,7 @@ func vfsFileDownloadHandler( var reader_at io.ReaderAt = &utils.ReaderAtter{Reader: file} - index, err := getIndex(config_obj, request.VfsPath) + index, err := getIndex(config_obj, path_spec) // If the file is sparse, we use the sparse reader. if err == nil && len(index.Ranges) > 0 { @@ -122,9 +140,9 @@ func vfsFileDownloadHandler( // From here on we sent the headers and we can not // really report an error to the client. - filename := strings.Replace(request.VfsPath, "\"", "_", -1) + filename := strings.Replace(path_spec.Base(), "\"", "_", -1) w.Header().Set("Content-Disposition", "attachment; filename="+ - url.PathEscape(path.Base(filename))) + url.PathEscape(filename)) w.Header().Set("Content-Type", "binary/octet-stream") w.WriteHeader(200) @@ -162,7 +180,8 @@ func getRows( ctx context.Context, config_obj *config_proto.Config, request *api_proto.GetTableRequest) ( - rows <-chan *ordereddict.Dict, close func(), log_path string, err error) { + rows <-chan *ordereddict.Dict, close func(), + log_path api.FSPathSpec, err error) { file_store_factory := file_store.GetFileStore(config_obj) // We want an event table. @@ -171,12 +190,12 @@ func getRows( config_obj, request.ClientId, request.FlowId, request.Artifact) if err != nil { - return nil, nil, "", err + return nil, nil, nil, err } log_path, err := path_manager.GetPathForWriting() if err != nil { - return nil, nil, "", err + return nil, nil, nil, err } rs_reader, err := result_sets.NewTimedResultSetReader( @@ -185,18 +204,13 @@ func getRows( return rs_reader.Rows(ctx), rs_reader.Close, log_path, err } else { - path_manager, err := getPathManager(config_obj, request) - if err != nil { - return nil, nil, "", err - } - - log_path, err := path_manager.GetPathForWriting() + log_path, err := getPathSpec(config_obj, request) if err != nil { - return nil, nil, "", err + return nil, nil, nil, err } rs_reader, err := result_sets.NewResultSetReader( - file_store_factory, path_manager) + file_store_factory, log_path) return rs_reader.Rows(ctx), rs_reader.Close, log_path, err } @@ -256,7 +270,7 @@ func downloadTable(config_obj *config_proto.Config) http.Handler { transform := getTransformer(config_obj, request) - download_name := strings.Replace(filepath.Base(log_path), "\"", "", -1) + download_name := strings.Replace(log_path.Base(), "\"", "", -1) // Log an audit event. userinfo := GetUserInfo(r.Context(), config_obj) @@ -329,93 +343,9 @@ func downloadTable(config_obj *config_proto.Config) http.Handler { }) } -// URL format: /api/v1/DownloadVFSFolder -func vfsFolderDownloadHandler( - config_obj *config_proto.Config) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - request := vfsFileDownloadRequest{} - decoder := schema.NewDecoder() - err := decoder.Decode(&request, r.URL.Query()) - if err != nil { - returnError(w, 404, err.Error()) - return - } - - if r.Method == "HEAD" { - returnError(w, 200, "Ok") - return - } - - // Log an audit event. - userinfo := GetUserInfo(r.Context(), config_obj) - - // This should never happen! - if userinfo.Name == "" { - returnError(w, 500, "Unauthenticated access.") - return - } - - // From here on we already sent the headers and we can - // not really report an error to the client. - filename := strings.Replace(request.VfsPath, "\"", "", -1) - w.Header().Set("Content-Disposition", "attachment; filename="+ - url.PathEscape(filename+".zip")) - w.Header().Set("Content-Type", "binary/octet-stream") - w.WriteHeader(200) - - logger := logging.GetLogger(config_obj, &logging.Audit) - logger.WithFields(logrus.Fields{ - "user": userinfo.Name, - "vfs_path": request.VfsPath, - "client_id": request.ClientId, - "remote": r.RemoteAddr, - }).Info("DownloadVFSPath") - - zip_writer := zip.NewWriter(w) - defer zip_writer.Close() - - file_store_factory := file_store.GetFileStore(config_obj) - - client_id := request.ClientId - hostname := services.GetHostname(client_id) - client_path_manager := paths.NewClientPathManager(client_id) - - db, _ := datastore.GetDB(config_obj) - _ = db.Walk(config_obj, client_path_manager.VFSDownloadInfoPath(request.VfsPath), - func(path_name string) error { - download_info := &flows_proto.VFSDownloadInfo{} - err := db.GetSubject(config_obj, path_name, download_info) - if err != nil { - logger.Warn("Cant open %s: %v", path_name, err) - return nil - } - - fd, err := file_store_factory.ReadFile(download_info.VfsPath) - if err != nil { - return err - } - - zh, err := zip_writer.Create(utils.CleanPathForZip( - path_name, client_id, hostname)) - if err != nil { - logger.Warn("Cant create zip %s: %v", path_name, err) - return nil - } - - _, err = utils.Copy(r.Context(), zh, fd) - if err != nil { - logger.Warn("Cant copy %s", path_name) - return nil - } - - return nil - }) - }) -} - func vfsGetBuffer( config_obj *config_proto.Config, - client_id string, vfs_path string, offset uint64, length uint32) ( + client_id string, vfs_path api.FSPathSpec, offset uint64, length uint32) ( *api_proto.VFSFileBuffer, error) { file, err := file_store.GetFileStore(config_obj).ReadFile(vfs_path) @@ -453,11 +383,12 @@ func vfsGetBuffer( } func getIndex(config_obj *config_proto.Config, - vfs_path string) (*actions_proto.Index, error) { + vfs_path api.FSPathSpec) (*actions_proto.Index, error) { index := &actions_proto.Index{} file_store_factory := file_store.GetFileStore(config_obj) - fd, err := file_store_factory.ReadFile(vfs_path + ".idx") + fd, err := file_store_factory.ReadFile( + vfs_path.SetType(api.PATH_TYPE_FILESTORE_SPARSE_IDX)) if err != nil { return nil, err } diff --git a/api/events.go b/api/events.go index 100a6e726d9..3276bd3144c 100644 --- a/api/events.go +++ b/api/events.go @@ -3,7 +3,6 @@ package api import ( "crypto/x509" "os" - "path" "sort" "strings" @@ -277,16 +276,16 @@ func listAvailableEventArtifacts( func getAllArtifacts( config_obj *config_proto.Config, - log_path string, + log_path api.FSPathSpec, seen map[string]*api_proto.AvailableEvent) error { file_store_factory := file_store.GetFileStore(config_obj) return file_store_factory.Walk(log_path, - func(full_path string, info os.FileInfo, err error) error { + func(full_path api.FSPathSpec, info os.FileInfo) error { if !info.IsDir() && info.Size() > 0 { - relative_path := strings.TrimPrefix(full_path, log_path) - artifact_name := strings.TrimLeft(path.Dir(relative_path), "/") + relative_path := full_path.Components()[len(log_path.Components()):] + artifact_name := strings.Join(relative_path, ".") event, pres := seen[artifact_name] if !pres { event = &api_proto.AvailableEvent{ diff --git a/api/mock/api_mock.go b/api/mock/api_mock.go index f8d83ec280f..7f7ad80e67f 100644 --- a/api/mock/api_mock.go +++ b/api/mock/api_mock.go @@ -561,6 +561,26 @@ func (mr *MockAPIClientMockRecorder) GetToolInfo(arg0, arg1 interface{}, arg2 .. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetToolInfo", reflect.TypeOf((*MockAPIClient)(nil).GetToolInfo), varargs...) } +// GetUserFavorites mocks base method. +func (m *MockAPIClient) GetUserFavorites(arg0 context.Context, arg1 *proto0.Favorite, arg2 ...grpc.CallOption) (*proto0.Favorites, error) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetUserFavorites", varargs...) + ret0, _ := ret[0].(*proto0.Favorites) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserFavorites indicates an expected call of GetUserFavorites. +func (mr *MockAPIClientMockRecorder) GetUserFavorites(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserFavorites", reflect.TypeOf((*MockAPIClient)(nil).GetUserFavorites), varargs...) +} + // GetUserUITraits mocks base method. func (m *MockAPIClient) GetUserUITraits(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc.CallOption) (*proto0.ApiGrrUser, error) { m.ctrl.T.Helper() @@ -1022,14 +1042,14 @@ func (mr *MockAPIClientMockRecorder) VFSGetBuffer(arg0, arg1 interface{}, arg2 . } // VFSListDirectory mocks base method. -func (m *MockAPIClient) VFSListDirectory(arg0 context.Context, arg1 *proto2.VFSListRequest, arg2 ...grpc.CallOption) (*proto2.VFSListResponse, error) { +func (m *MockAPIClient) VFSListDirectory(arg0 context.Context, arg1 *proto0.VFSListRequest, arg2 ...grpc.CallOption) (*proto0.VFSListResponse, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "VFSListDirectory", varargs...) - ret0, _ := ret[0].(*proto2.VFSListResponse) + ret0, _ := ret[0].(*proto0.VFSListResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1062,14 +1082,14 @@ func (mr *MockAPIClientMockRecorder) VFSRefreshDirectory(arg0, arg1 interface{}, } // VFSStatDirectory mocks base method. -func (m *MockAPIClient) VFSStatDirectory(arg0 context.Context, arg1 *proto2.VFSListRequest, arg2 ...grpc.CallOption) (*proto2.VFSListResponse, error) { +func (m *MockAPIClient) VFSStatDirectory(arg0 context.Context, arg1 *proto0.VFSListRequest, arg2 ...grpc.CallOption) (*proto0.VFSListResponse, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "VFSStatDirectory", varargs...) - ret0, _ := ret[0].(*proto2.VFSListResponse) + ret0, _ := ret[0].(*proto0.VFSListResponse) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1082,7 +1102,7 @@ func (mr *MockAPIClientMockRecorder) VFSStatDirectory(arg0, arg1 interface{}, ar } // VFSStatDownload mocks base method. -func (m *MockAPIClient) VFSStatDownload(arg0 context.Context, arg1 *proto2.VFSStatDownloadRequest, arg2 ...grpc.CallOption) (*proto2.VFSDownloadInfo, error) { +func (m *MockAPIClient) VFSStatDownload(arg0 context.Context, arg1 *proto0.VFSStatDownloadRequest, arg2 ...grpc.CallOption) (*proto2.VFSDownloadInfo, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { diff --git a/api/notebooks.go b/api/notebooks.go index a7f85fce19e..227537c6437 100644 --- a/api/notebooks.go +++ b/api/notebooks.go @@ -7,7 +7,6 @@ import ( "encoding/binary" "fmt" "os" - "path" "strings" "time" @@ -24,9 +23,11 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/datastore" file_store "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/file_store/api" "www.velocidex.com/golang/velociraptor/flows" "www.velocidex.com/golang/velociraptor/json" "www.velocidex.com/golang/velociraptor/logging" + "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/reporting" "www.velocidex.com/golang/velociraptor/services" users "www.velocidex.com/golang/velociraptor/users" @@ -71,7 +72,7 @@ func (self *ApiServer) GetNotebooks( // We want a single notebook metadata. if in.NotebookId != "" { - notebook_path_manager := reporting.NewNotebookPathManager( + notebook_path_manager := paths.NewNotebookPathManager( in.NotebookId) notebook := &api_proto.NotebookMetadata{} err := db.GetSubject(self.config, notebook_path_manager.Path(), @@ -91,7 +92,7 @@ func (self *ApiServer) GetNotebooks( // An error here just means there are no AvailableDownloads. notebook.AvailableDownloads, _ = getAvailableDownloadFiles(self.config, - path.Dir(notebook_path_manager.HtmlExport())) + notebook_path_manager.HtmlExport().Dir()) notebook.Timelines = getAvailableTimelines( self.config, notebook_path_manager) @@ -190,7 +191,7 @@ func (self *ApiServer) NewNotebook( // Store the notebook metadata first before creating the // cells. Calculating the cells will try to open the notebook. - notebook_path_manager := reporting.NewNotebookPathManager(in.NotebookId) + notebook_path_manager := paths.NewNotebookPathManager(in.NotebookId) err = db.SetSubject(self.config, notebook_path_manager.Path(), in) if err != nil { return nil, err @@ -329,6 +330,13 @@ func getDefaultCellsForSources(config_obj *config_proto.Config, // If the artifact_source defines a notebook, let it do its own thing. if len(artifact_source.Notebook) > 0 { for _, cell := range artifact_source.Notebook { + for _, i := range cell.Env { + env = append(env, &api_proto.Env{ + Key: i.Key, + Value: i.Value, + }) + } + result = append(result, &api_proto.NotebookCellRequest{ Type: cell.Type, Env: env, @@ -387,7 +395,7 @@ func (self *ApiServer) NewNotebookCell( } notebook := &api_proto.NotebookMetadata{} - notebook_path_manager := reporting.NewNotebookPathManager(in.NotebookId) + notebook_path_manager := paths.NewNotebookPathManager(in.NotebookId) err = db.GetSubject(self.config, notebook_path_manager.Path(), notebook) if err != nil { return nil, err @@ -479,7 +487,7 @@ func (self *ApiServer) UpdateNotebook( } old_notebook := &api_proto.NotebookMetadata{} - notebook_path_manager := reporting.NewNotebookPathManager(in.NotebookId) + notebook_path_manager := paths.NewNotebookPathManager(in.NotebookId) err = db.GetSubject(self.config, notebook_path_manager.Path(), old_notebook) if err != nil { return nil, err @@ -555,7 +563,7 @@ func (self *ApiServer) GetNotebookCell( } // Check the user is allowed to manipulate this notebook. - notebook_path_manager := reporting.NewNotebookPathManager(in.NotebookId) + notebook_path_manager := paths.NewNotebookPathManager(in.NotebookId) notebook_metadata := &api_proto.NotebookMetadata{} err = db.GetSubject(self.config, @@ -618,7 +626,7 @@ func (self *ApiServer) UpdateNotebookCell( } // Check that the user has access to this notebook. - notebook_path_manager := reporting.NewNotebookPathManager(in.NotebookId) + notebook_path_manager := paths.NewNotebookPathManager(in.NotebookId) notebook_metadata := &api_proto.NotebookMetadata{} db, err := datastore.GetDB(self.config) if err != nil { @@ -661,7 +669,8 @@ func (self *ApiServer) updateNotebookCell( } // And store it for next time. - notebook_path_manager := reporting.NewNotebookPathManager(notebook_metadata.NotebookId) + notebook_path_manager := paths.NewNotebookPathManager( + notebook_metadata.NotebookId) err = db.SetSubject(self.config, notebook_path_manager.Cell(in.CellId).Path(), notebook_cell) @@ -818,8 +827,8 @@ func (self *ApiServer) CancelNotebookCell( if err != nil { return nil, err } - notebook_cell_path_manager := reporting.NewNotebookPathManager(in.NotebookId). - Cell(in.CellId) + notebook_cell_path_manager := paths.NewNotebookPathManager( + in.NotebookId).Cell(in.CellId) notebook_cell := &api_proto.NotebookCell{} err = db.GetSubject(self.config, notebook_cell_path_manager.Path(), notebook_cell) @@ -862,8 +871,8 @@ func (self *ApiServer) UploadNotebookAttachment( } filename := NewNotebookAttachmentId() + in.Filename - full_path := path.Join("/notebooks", in.NotebookId, - string(datastore.SanitizeString(filename))) + full_path := paths.NewNotebookPathManager(in.NotebookId). + Attachment(filename) file_store_factory := file_store.GetFileStore(self.config) fd, err := file_store_factory.WriteFile(full_path) if err != nil { @@ -877,7 +886,7 @@ func (self *ApiServer) UploadNotebookAttachment( } result := &api_proto.NotebookFileUploadResponse{ - Url: full_path, + Url: full_path.AsClientPath(), } return result, nil } @@ -921,7 +930,7 @@ func exportZipNotebook( } notebook := &api_proto.NotebookMetadata{} - notebook_path_manager := reporting.NewNotebookPathManager(notebook_id) + notebook_path_manager := paths.NewNotebookPathManager(notebook_id) err = db.GetSubject(config_obj, notebook_path_manager.Path(), notebook) if err != nil { return err @@ -933,8 +942,9 @@ func exportZipNotebook( file_store_factory := file_store.GetFileStore(config_obj) filename := notebook_path_manager.ZipExport() + lock_file_name := filename.SetType(api.PATH_TYPE_FILESTORE_LOCK) - lock_file, err := file_store_factory.WriteFile(filename + ".lock") + lock_file, err := file_store_factory.WriteFile(lock_file_name) if err != nil { return err } @@ -945,7 +955,7 @@ func exportZipNotebook( go func() { defer func() { - _ = file_store_factory.Delete(filename + ".lock") + _ = file_store_factory.Delete(lock_file_name) }() defer cancel() @@ -974,7 +984,7 @@ func exportHTMLNotebook(config_obj *config_proto.Config, } notebook := &api_proto.NotebookMetadata{} - notebook_path_manager := reporting.NewNotebookPathManager(notebook_id) + notebook_path_manager := paths.NewNotebookPathManager(notebook_id) err = db.GetSubject(config_obj, notebook_path_manager.Path(), notebook) if err != nil { return err @@ -986,8 +996,9 @@ func exportHTMLNotebook(config_obj *config_proto.Config, file_store_factory := file_store.GetFileStore(config_obj) filename := notebook_path_manager.HtmlExport() + lock_file_name := filename.SetType(api.PATH_TYPE_FILESTORE_LOCK) - lock_file, err := file_store_factory.WriteFile(filename + ".lock") + lock_file, err := file_store_factory.WriteFile(lock_file_name) if err != nil { return err } @@ -1002,7 +1013,7 @@ func exportHTMLNotebook(config_obj *config_proto.Config, sub_ctx, cancel := context.WithTimeout(context.Background(), time.Hour) go func() { - defer func() { _ = file_store_factory.Delete(filename + ".lock") }() + defer func() { _ = file_store_factory.Delete(lock_file_name) }() defer writer.Close() defer cancel() @@ -1024,24 +1035,24 @@ func exportHTMLNotebook(config_obj *config_proto.Config, func getAvailableTimelines( config_obj *config_proto.Config, - path_manager *reporting.NotebookPathManager) []string { + path_manager *paths.NotebookPathManager) []string { result := []string{} db, err := datastore.GetDB(config_obj) - files, err := db.ListChildren(config_obj, path_manager.TimelineDir(), - 0, 1000) + files, err := db.ListChildren( + config_obj, path_manager.SuperTimelineDir(), 0, 1000) if err != nil { return nil } for _, f := range files { - result = append(result, utils.Base(f)) + result = append(result, f.Base()) } return result } func getAvailableDownloadFiles(config_obj *config_proto.Config, - download_path string) (*api_proto.AvailableDownloads, error) { + download_path api.FSPathSpec) (*api_proto.AvailableDownloads, error) { result := &api_proto.AvailableDownloads{} file_store_factory := file_store.GetFileStore(config_obj) @@ -1065,8 +1076,9 @@ func getAvailableDownloadFiles(config_obj *config_proto.Config, } result.Files = append(result.Files, &api_proto.AvailableDownloadFile{ - Name: item.Name(), - Path: path.Join(download_path, item.Name()), + Name: item.Name(), + Path: download_path.AddChild( + item.Name()).AsClientPath(), Size: uint64(item.Size()), Date: fmt.Sprintf("%v", item.ModTime()), Complete: is_complete(item.Name()), @@ -1093,6 +1105,40 @@ func updateCellContents( cell_type = strings.ToLower(cell_type) + // Create a new cell to set the result in. + make_cell := func(output string) *api_proto.NotebookCell { + messages := tmpl.Messages() + + encoded_data, err := json.Marshal(tmpl.Data) + if err != nil { + messages = append(messages, + fmt.Sprintf("Error: %v", err)) + } + + return &api_proto.NotebookCell{ + Input: original_input, + Output: output, + Data: string(encoded_data), + Messages: tmpl.Messages(), + CellId: cell_id, + Type: cell_type, + Env: env, + Timestamp: time.Now().Unix(), + CurrentlyEditing: currently_editing, + Duration: int64(time.Since(tmpl.Start).Seconds()), + } + } + + // If an error occurs it is important to ensure the cell is + // still written with an error message. + make_error_cell := func(err error) (*api_proto.NotebookCell, error) { + notebook_cell := make_cell("") + notebook_cell.Messages = append(notebook_cell.Messages, + fmt.Sprintf("Error: %v", err)) + setCell(config_obj, notebook_id, notebook_cell) + return notebook_cell, err + } + switch cell_type { case "markdown", "md": @@ -1100,7 +1146,7 @@ func updateCellContents( // template. output, err = tmpl.Execute(&artifacts_proto.Report{Template: input}) if err != nil { - return nil, err + return make_error_cell(err) } case "vql": @@ -1133,36 +1179,19 @@ func updateCellContents( } fragment_output, err := tmpl.Execute(&artifacts_proto.Report{Template: input}) if err != nil { - return nil, err + return make_error_cell(err) } output += fragment_output } } default: - return nil, errors.New("Unsupported cell type.") - } - - encoded_data, err := json.Marshal(tmpl.Data) - if err != nil { - return nil, err + return make_error_cell(errors.New("Unsupported cell type.")) } tmpl.Close() - notebook_cell := &api_proto.NotebookCell{ - Input: original_input, - Output: output, - Data: string(encoded_data), - Messages: tmpl.Messages(), - CellId: cell_id, - Type: cell_type, - Env: env, - Timestamp: time.Now().Unix(), - CurrentlyEditing: currently_editing, - Duration: int64(time.Since(tmpl.Start).Seconds()), - } - + notebook_cell := make_cell(output) return notebook_cell, setCell(config_obj, notebook_id, notebook_cell) } @@ -1177,7 +1206,7 @@ func setCell( } // And store it for next time. - notebook_path_manager := reporting.NewNotebookPathManager(notebook_id) + notebook_path_manager := paths.NewNotebookPathManager(notebook_id) err = db.SetSubject(config_obj, notebook_path_manager.Cell(notebook_cell.CellId).Path(), notebook_cell) diff --git a/api/proto/api.pb.go b/api/proto/api.pb.go index c187f4cfd32..606eb35e987 100644 --- a/api/proto/api.pb.go +++ b/api/proto/api.pb.go @@ -173,8 +173,10 @@ type VFSRefreshDirectoryRequest struct { unknownFields protoimpl.UnknownFields ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - VfsPath string `protobuf:"bytes,2,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` - Depth uint64 `protobuf:"varint,3,opt,name=depth,proto3" json:"depth,omitempty"` + // Deprecated + XXXXvfsPath string `protobuf:"bytes,2,opt,name=XXXXvfs_path,json=XXXXvfsPath,proto3" json:"XXXXvfs_path,omitempty"` + VfsComponents []string `protobuf:"bytes,4,rep,name=vfs_components,json=vfsComponents,proto3" json:"vfs_components,omitempty"` + Depth uint64 `protobuf:"varint,3,opt,name=depth,proto3" json:"depth,omitempty"` } func (x *VFSRefreshDirectoryRequest) Reset() { @@ -216,13 +218,20 @@ func (x *VFSRefreshDirectoryRequest) GetClientId() string { return "" } -func (x *VFSRefreshDirectoryRequest) GetVfsPath() string { +func (x *VFSRefreshDirectoryRequest) GetXXXXvfsPath() string { if x != nil { - return x.VfsPath + return x.XXXXvfsPath } return "" } +func (x *VFSRefreshDirectoryRequest) GetVfsComponents() []string { + if x != nil { + return x.VfsComponents + } + return nil +} + func (x *VFSRefreshDirectoryRequest) GetDepth() uint64 { if x != nil { return x.Depth @@ -235,11 +244,11 @@ type VFSFileBuffer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - VfsPath string `protobuf:"bytes,2,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` - Offset uint64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` - Length uint32 `protobuf:"varint,4,opt,name=length,proto3" json:"length,omitempty"` - Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + Offset uint64 `protobuf:"varint,3,opt,name=offset,proto3" json:"offset,omitempty"` + Length uint32 `protobuf:"varint,4,opt,name=length,proto3" json:"length,omitempty"` + Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` + Components []string `protobuf:"bytes,6,rep,name=components,proto3" json:"components,omitempty"` } func (x *VFSFileBuffer) Reset() { @@ -281,13 +290,6 @@ func (x *VFSFileBuffer) GetClientId() string { return "" } -func (x *VFSFileBuffer) GetVfsPath() string { - if x != nil { - return x.VfsPath - } - return "" -} - func (x *VFSFileBuffer) GetOffset() uint64 { if x != nil { return x.Offset @@ -309,6 +311,13 @@ func (x *VFSFileBuffer) GetData() []byte { return nil } +func (x *VFSFileBuffer) GetComponents() []string { + if x != nil { + return x.Components + } + return nil +} + type NotificationRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -573,416 +582,420 @@ var file_api_proto_rawDesc = []byte{ 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0b, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x63, 0x73, 0x76, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x63, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, - 0x2c, 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x22, 0x0a, - 0x08, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, - 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, - 0x6e, 0x22, 0x35, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x25, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, - 0x6c, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xde, 0x01, 0x0a, 0x1a, 0x56, 0x46, 0x53, - 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe2, 0xfc, 0xe3, 0xc4, - 0x01, 0x1f, 0x0a, 0x06, 0x52, 0x44, 0x46, 0x55, 0x52, 0x4e, 0x12, 0x12, 0x54, 0x68, 0x65, 0x20, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x1a, 0x01, - 0x02, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x08, 0x76, - 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x21, 0x12, 0x1f, 0x54, 0x68, 0x65, 0x20, 0x56, 0x46, 0x53, 0x20, 0x50, - 0x61, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x66, 0x69, 0x6c, 0x65, - 0x73, 0x20, 0x69, 0x6e, 0x20, 0x2e, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, - 0x38, 0x0a, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x22, - 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1c, 0x12, 0x1a, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x6f, 0x66, - 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, 0x72, 0x65, 0x66, 0x72, 0x65, - 0x73, 0x68, 0x52, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x22, 0xb4, 0x01, 0x0a, 0x0d, 0x56, 0x46, - 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe2, 0xfc, 0xe3, 0xc4, - 0x01, 0x21, 0x12, 0x1f, 0x54, 0x68, 0x65, 0x20, 0x56, 0x46, 0x53, 0x20, 0x50, 0x61, 0x74, 0x68, - 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x20, 0x69, - 0x6e, 0x20, 0x2e, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x06, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, - 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, - 0x22, 0x51, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, 0x61, - 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, - 0x41, 0x6c, 0x6c, 0x22, 0x38, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, 0x64, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x3d, 0x0a, - 0x0d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x22, 0x7a, 0x0a, 0x10, - 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, - 0x77, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x32, 0xdd, 0x2b, 0x0a, 0x03, 0x41, 0x50, 0x49, - 0x12, 0x52, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x0b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x75, 0x6e, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6e, - 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x59, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6e, 0x74, - 0x73, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, - 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x73, 0x12, - 0x46, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x75, 0x6e, 0x74, 0x22, 0x17, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x69, 0x66, - 0x79, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x75, - 0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4d, 0x6f, 0x64, 0x69, - 0x66, 0x79, 0x48, 0x75, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5d, 0x0a, 0x0c, 0x47, 0x65, 0x74, - 0x48, 0x75, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, - 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x48, - 0x75, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x67, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x48, - 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x73, 0x12, 0x64, 0x0a, 0x0d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x0d, 0x76, 0x66, 0x73, 0x5f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2c, + 0x0a, 0x11, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x22, 0x0a, 0x08, + 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x22, 0x35, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x25, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x61, 0x6c, + 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0xe4, 0x01, 0x0a, 0x1a, 0x56, 0x46, 0x53, 0x52, + 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, + 0x1f, 0x0a, 0x06, 0x52, 0x44, 0x46, 0x55, 0x52, 0x4e, 0x12, 0x12, 0x54, 0x68, 0x65, 0x20, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x1a, 0x01, 0x02, + 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x58, 0x58, + 0x58, 0x58, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x58, 0x58, 0x58, 0x58, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, + 0x0e, 0x76, 0x66, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x76, 0x66, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x42, 0x22, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1c, 0x12, 0x1a, 0x44, 0x65, 0x70, + 0x74, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x20, + 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x52, 0x05, 0x64, 0x65, 0x70, 0x74, 0x68, 0x22, 0x90, + 0x01, 0x0a, 0x0d, 0x56, 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, + 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x12, 0x0a, + 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x73, 0x22, 0x51, 0x0a, 0x13, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x5f, + 0x61, 0x6c, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x79, 0x41, 0x6c, 0x6c, 0x22, 0x38, 0x0a, 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x75, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x6f, + 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x3d, + 0x0a, 0x0d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x22, 0x7a, 0x0a, + 0x10, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1b, 0x0a, + 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, + 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6c, 0x6f, + 0x77, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x6a, 0x73, 0x6f, 0x6e, 0x6c, 0x32, 0xb6, 0x2c, 0x0a, 0x03, 0x41, 0x50, + 0x49, 0x12, 0x52, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x75, 0x6e, 0x74, 0x12, + 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x75, 0x6e, 0x74, 0x1a, 0x18, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x48, 0x75, + 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x59, 0x0a, 0x09, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6e, + 0x74, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, + 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x73, + 0x12, 0x46, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x15, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x75, 0x6e, 0x74, 0x22, + 0x17, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x0a, 0x4d, 0x6f, 0x64, 0x69, + 0x66, 0x79, 0x48, 0x75, 0x6e, 0x74, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, + 0x75, 0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1d, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4d, 0x6f, 0x64, + 0x69, 0x66, 0x79, 0x48, 0x75, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5d, 0x0a, 0x0c, 0x47, 0x65, + 0x74, 0x48, 0x75, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, + 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, + 0x48, 0x75, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, 0x12, 0x67, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x48, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x12, 0x64, 0x0a, 0x0d, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x69, + 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, + 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5f, 0x0a, 0x0c, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x50, 0x49, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, + 0x22, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x0b, 0x4c, 0x69, 0x73, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x5d, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, + 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x41, 0x70, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x7d, 0x12, 0x72, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x12, 0x25, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1e, 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x01, 0x2a, 0x12, + 0x99, 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x6c, 0x6f, + 0x77, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x58, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x52, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, + 0x73, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x5a, 0x2c, 0x42, + 0x2a, 0x0a, 0x04, 0x48, 0x45, 0x41, 0x44, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, 0x2f, + 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x55, 0x49, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x14, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x79, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5f, 0x0a, 0x0c, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x50, 0x49, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x22, - 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x67, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x73, 0x12, 0x5d, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x17, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x41, 0x70, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, - 0x12, 0x72, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x12, 0x25, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x68, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, - 0x22, 0x19, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x3a, 0x01, 0x2a, 0x12, 0x99, - 0x01, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, - 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, - 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x58, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x52, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, - 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x5a, 0x2c, 0x42, 0x2a, - 0x0a, 0x04, 0x48, 0x45, 0x41, 0x44, 0x12, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x73, 0x2f, 0x7b, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x5d, 0x0a, 0x0f, 0x47, 0x65, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x55, 0x49, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, - 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, - 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x55, 0x49, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x12, 0x66, 0x0a, 0x0d, 0x53, 0x65, 0x74, - 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, - 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x53, 0x65, 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x01, - 0x2a, 0x12, 0x4a, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x73, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x6f, 0x0a, - 0x10, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, + 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x55, 0x49, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x12, 0x66, 0x0a, 0x0d, 0x53, 0x65, + 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x31, 0x2f, 0x53, 0x65, 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, + 0x01, 0x2a, 0x12, 0x4a, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x57, + 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x46, 0x61, 0x76, 0x6f, 0x72, 0x69, 0x74, + 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x61, 0x76, 0x6f, 0x72, + 0x69, 0x74, 0x65, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x61, 0x76, 0x6f, + 0x72, 0x69, 0x74, 0x65, 0x73, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x12, 0x6f, 0x0a, 0x10, 0x56, 0x46, 0x53, 0x4c, 0x69, + 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x56, 0x46, 0x53, 0x4c, + 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x7b, 0x63, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x82, 0x01, 0x0a, 0x13, 0x56, 0x46, 0x53, + 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, + 0x12, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x52, 0x65, 0x66, 0x72, + 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x22, 0x1b, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x56, 0x46, 0x53, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, + 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, + 0x10, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x12, 0x24, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x79, 0x2f, 0x7b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x12, 0x82, - 0x01, 0x0a, 0x13, 0x56, 0x46, 0x53, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, - 0x46, 0x53, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x20, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x56, 0x46, 0x53, - 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, - 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, 0x10, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, - 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, - 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x69, 0x0a, 0x0f, 0x56, 0x46, 0x53, 0x53, - 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1d, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, - 0x66, 0x6f, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x6f, 0x61, 0x64, 0x12, 0x55, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, - 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x75, 0x0a, 0x0f, 0x43, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x20, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x3a, 0x01, - 0x2a, 0x12, 0x5c, 0x0a, 0x0a, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x12, - 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, - 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x3a, 0x01, 0x2a, 0x12, - 0x5e, 0x0a, 0x0b, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x15, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, - 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, - 0x2f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x3a, 0x01, 0x2a, 0x12, - 0x5b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, - 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, - 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1e, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, - 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x67, 0x0a, 0x0f, + 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x31, 0x2f, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x79, 0x12, 0x69, 0x0a, 0x0f, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, + 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x1f, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x56, 0x46, + 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x55, 0x0a, + 0x08, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x12, 0x12, 0x10, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x54, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x75, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, + 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x5c, 0x0a, 0x0a, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, + 0x6f, 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x17, 0x22, 0x12, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x46, 0x6c, 0x6f, 0x77, 0x3a, 0x01, 0x2a, 0x12, 0x5e, 0x0a, 0x0b, 0x41, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x72, 0x74, 0x46, 0x6c, 0x6f, + 0x77, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x41, 0x72, 0x63, 0x68, 0x69, + 0x76, 0x65, 0x46, 0x6c, 0x6f, 0x77, 0x3a, 0x01, 0x2a, 0x12, 0x5b, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x46, 0x6c, 0x6f, 0x77, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x44, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x67, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, + 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1f, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, - 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, - 0x70, 0x69, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x44, 0x65, 0x74, - 0x61, 0x69, 0x6c, 0x73, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x46, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x71, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x77, - 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, - 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x64, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, - 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x69, - 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, - 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, - 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x53, 0x65, 0x74, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x41, 0x50, 0x49, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, 0x12, - 0x6e, 0x0a, 0x10, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, - 0x61, 0x63, 0x6b, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, - 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, - 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x6f, 0x61, 0x64, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x3a, 0x01, 0x2a, 0x12, - 0x44, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x1a, 0x0b, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, - 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6f, - 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x47, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, - 0x6c, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x22, 0x1e, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x3a, 0x01, 0x2a, 0x12, 0x5c, - 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, - 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x7a, 0x0a, 0x18, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, - 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x71, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x22, 0x28, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, - 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x74, + 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x25, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, + 0x4b, 0x65, 0x79, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x64, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x12, 0x69, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x46, + 0x69, 0x6c, 0x65, 0x12, 0x64, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, + 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x50, 0x49, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x6e, 0x0a, 0x10, 0x4c, 0x6f, 0x61, + 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x12, 0x14, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, + 0x66, 0x65, 0x72, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x61, 0x64, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x6f, 0x61, 0x64, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x50, 0x61, 0x63, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x44, 0x0a, 0x0b, 0x47, 0x65, 0x74, + 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, + 0x6f, 0x6c, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x47, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0b, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x1a, 0x0b, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, + 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x54, 0x6f, 0x6f, + 0x6c, 0x49, 0x6e, 0x66, 0x6f, 0x3a, 0x01, 0x2a, 0x12, 0x5c, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, + 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, + 0x22, 0x11, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x52, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x7a, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, + 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x1c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, + 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, - 0x72, 0x67, 0x73, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, - 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, - 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x6e, 0x69, - 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x75, - 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, - 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, - 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x78, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, - 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, - 0x9c, 0x01, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, - 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x27, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, - 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, - 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x74, - 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, - 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, - 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x5a, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, - 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, - 0x6b, 0x73, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, - 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, - 0x12, 0x5f, 0x0a, 0x0b, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, - 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, - 0x2a, 0x12, 0x65, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, - 0x6f, 0x6f, 0x6b, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, - 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x17, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0f, 0x4e, 0x65, 0x77, 0x4e, - 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, - 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x75, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x43, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x22, 0x12, 0x20, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x78, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, + 0x61, 0x62, 0x6c, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x53, 0x65, + 0x74, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x9c, 0x01, 0x0a, 0x19, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x76, 0x61, + 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x26, 0x22, 0x21, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x73, 0x3a, 0x01, 0x2a, 0x12, 0x74, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, + 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, + 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x5a, + 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x1a, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, + 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x22, 0x1c, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x16, 0x12, 0x14, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, + 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x73, 0x12, 0x5f, 0x0a, 0x0b, 0x4e, 0x65, + 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, + 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x1e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x18, 0x22, 0x13, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, + 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x65, 0x0a, 0x0e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x17, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, + 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, + 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, + 0x01, 0x2a, 0x12, 0x6a, 0x0a, 0x0f, 0x4e, 0x65, 0x77, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, + 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, + 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x4e, 0x65, 0x77, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x63, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, + 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, + 0x6c, 0x6c, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, + 0x65, 0x6c, 0x6c, 0x12, 0x6c, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, + 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, + 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, + 0x2a, 0x12, 0x6f, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, - 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, - 0x12, 0x17, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x47, 0x65, 0x74, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x6c, 0x0a, 0x12, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, - 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, - 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, - 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x2f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, - 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x6f, 0x0a, 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, - 0x6c, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, - 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, - 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x25, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x43, 0x65, 0x6c, 0x6c, 0x3a, + 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, + 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, + 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x22, + 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, + 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x8c, 0x01, 0x0a, 0x18, 0x55, 0x70, 0x6c, 0x6f, 0x61, + 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, + 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, + 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, + 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, + 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x41, 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, + 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x69, 0x0a, 0x0e, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4e, + 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2d, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x27, 0x22, 0x22, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x44, 0x6f, 0x77, - 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x3a, 0x01, 0x2a, 0x12, 0x8c, 0x01, 0x0a, - 0x18, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x41, - 0x74, 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, 0x6c, 0x65, 0x55, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x46, 0x69, 0x6c, 0x65, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x22, 0x20, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, - 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x41, 0x74, - 0x74, 0x61, 0x63, 0x68, 0x6d, 0x65, 0x6e, 0x74, 0x3a, 0x01, 0x2a, 0x12, 0x69, 0x0a, 0x0e, 0x45, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x12, 0x1c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, - 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, 0x12, 0x3c, 0x0a, 0x0c, 0x56, 0x46, 0x53, 0x47, 0x65, 0x74, - 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, - 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x14, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, - 0x65, 0x72, 0x22, 0x00, 0x12, 0x38, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, - 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3b, - 0x0a, 0x0a, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x0a, 0x50, - 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0a, - 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, - 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, - 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, - 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x21, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x45, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x01, 0x2a, + 0x12, 0x3c, 0x0a, 0x0c, 0x56, 0x46, 0x53, 0x47, 0x65, 0x74, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, + 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, + 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, + 0x46, 0x53, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x22, 0x00, 0x12, 0x38, + 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x56, 0x51, 0x4c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, + 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3b, 0x0a, 0x0a, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3f, 0x0a, 0x0a, 0x50, 0x75, 0x73, 0x68, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x50, 0x75, 0x73, 0x68, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0a, 0x57, 0x72, 0x69, 0x74, 0x65, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x00, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, + 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x76, + 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1020,46 +1033,48 @@ var file_api_proto_goTypes = []interface{}{ (*ApiFlowRequest)(nil), // 18: proto.ApiFlowRequest (*empty.Empty)(nil), // 19: google.protobuf.Empty (*SetGUIOptionsRequest)(nil), // 20: proto.SetGUIOptionsRequest - (*proto.VFSListRequest)(nil), // 21: proto.VFSListRequest - (*proto.VFSStatDownloadRequest)(nil), // 22: proto.VFSStatDownloadRequest - (*proto.ArtifactCollectorArgs)(nil), // 23: proto.ArtifactCollectorArgs - (*GetArtifactsRequest)(nil), // 24: proto.GetArtifactsRequest - (*GetArtifactRequest)(nil), // 25: proto.GetArtifactRequest - (*SetArtifactRequest)(nil), // 26: proto.SetArtifactRequest - (*proto1.Tool)(nil), // 27: proto.Tool - (*GetReportRequest)(nil), // 28: proto.GetReportRequest - (*proto.ClientEventTable)(nil), // 29: proto.ClientEventTable - (*ListAvailableEventResultsRequest)(nil), // 30: proto.ListAvailableEventResultsRequest - (*CreateDownloadRequest)(nil), // 31: proto.CreateDownloadRequest - (*NotebookCellRequest)(nil), // 32: proto.NotebookCellRequest - (*NotebookMetadata)(nil), // 33: proto.NotebookMetadata - (*NotebookExportRequest)(nil), // 34: proto.NotebookExportRequest - (*NotebookFileUploadRequest)(nil), // 35: proto.NotebookFileUploadRequest - (*proto2.VQLCollectorArgs)(nil), // 36: proto.VQLCollectorArgs - (*proto2.VQLResponse)(nil), // 37: proto.VQLResponse - (*ListHuntsResponse)(nil), // 38: proto.ListHuntsResponse - (*GetTableResponse)(nil), // 39: proto.GetTableResponse - (*APIResponse)(nil), // 40: proto.APIResponse - (*SearchClientsResponse)(nil), // 41: proto.SearchClientsResponse - (*ApiClient)(nil), // 42: proto.ApiClient - (*ApiFlowResponse)(nil), // 43: proto.ApiFlowResponse - (*ApiGrrUser)(nil), // 44: proto.ApiGrrUser - (*Users)(nil), // 45: proto.Users - (*proto.VFSListResponse)(nil), // 46: proto.VFSListResponse - (*proto.ArtifactCollectorResponse)(nil), // 47: proto.ArtifactCollectorResponse - (*proto.VFSDownloadInfo)(nil), // 48: proto.VFSDownloadInfo - (*FlowDetails)(nil), // 49: proto.FlowDetails - (*ApiFlowRequestDetails)(nil), // 50: proto.ApiFlowRequestDetails - (*KeywordCompletions)(nil), // 51: proto.KeywordCompletions - (*proto1.ArtifactDescriptors)(nil), // 52: proto.ArtifactDescriptors - (*GetArtifactResponse)(nil), // 53: proto.GetArtifactResponse - (*LoadArtifactPackResponse)(nil), // 54: proto.LoadArtifactPackResponse - (*GetReportResponse)(nil), // 55: proto.GetReportResponse - (*ListAvailableEventResultsResponse)(nil), // 56: proto.ListAvailableEventResultsResponse - (*CreateDownloadResponse)(nil), // 57: proto.CreateDownloadResponse - (*Notebooks)(nil), // 58: proto.Notebooks - (*NotebookCell)(nil), // 59: proto.NotebookCell - (*NotebookFileUploadResponse)(nil), // 60: proto.NotebookFileUploadResponse + (*Favorite)(nil), // 21: proto.Favorite + (*VFSListRequest)(nil), // 22: proto.VFSListRequest + (*VFSStatDownloadRequest)(nil), // 23: proto.VFSStatDownloadRequest + (*proto.ArtifactCollectorArgs)(nil), // 24: proto.ArtifactCollectorArgs + (*GetArtifactsRequest)(nil), // 25: proto.GetArtifactsRequest + (*GetArtifactRequest)(nil), // 26: proto.GetArtifactRequest + (*SetArtifactRequest)(nil), // 27: proto.SetArtifactRequest + (*proto1.Tool)(nil), // 28: proto.Tool + (*GetReportRequest)(nil), // 29: proto.GetReportRequest + (*proto.ClientEventTable)(nil), // 30: proto.ClientEventTable + (*ListAvailableEventResultsRequest)(nil), // 31: proto.ListAvailableEventResultsRequest + (*CreateDownloadRequest)(nil), // 32: proto.CreateDownloadRequest + (*NotebookCellRequest)(nil), // 33: proto.NotebookCellRequest + (*NotebookMetadata)(nil), // 34: proto.NotebookMetadata + (*NotebookExportRequest)(nil), // 35: proto.NotebookExportRequest + (*NotebookFileUploadRequest)(nil), // 36: proto.NotebookFileUploadRequest + (*proto2.VQLCollectorArgs)(nil), // 37: proto.VQLCollectorArgs + (*proto2.VQLResponse)(nil), // 38: proto.VQLResponse + (*ListHuntsResponse)(nil), // 39: proto.ListHuntsResponse + (*GetTableResponse)(nil), // 40: proto.GetTableResponse + (*APIResponse)(nil), // 41: proto.APIResponse + (*SearchClientsResponse)(nil), // 42: proto.SearchClientsResponse + (*ApiClient)(nil), // 43: proto.ApiClient + (*ApiFlowResponse)(nil), // 44: proto.ApiFlowResponse + (*ApiGrrUser)(nil), // 45: proto.ApiGrrUser + (*Users)(nil), // 46: proto.Users + (*Favorites)(nil), // 47: proto.Favorites + (*VFSListResponse)(nil), // 48: proto.VFSListResponse + (*proto.ArtifactCollectorResponse)(nil), // 49: proto.ArtifactCollectorResponse + (*proto.VFSDownloadInfo)(nil), // 50: proto.VFSDownloadInfo + (*FlowDetails)(nil), // 51: proto.FlowDetails + (*ApiFlowRequestDetails)(nil), // 52: proto.ApiFlowRequestDetails + (*KeywordCompletions)(nil), // 53: proto.KeywordCompletions + (*proto1.ArtifactDescriptors)(nil), // 54: proto.ArtifactDescriptors + (*GetArtifactResponse)(nil), // 55: proto.GetArtifactResponse + (*LoadArtifactPackResponse)(nil), // 56: proto.LoadArtifactPackResponse + (*GetReportResponse)(nil), // 57: proto.GetReportResponse + (*ListAvailableEventResultsResponse)(nil), // 58: proto.ListAvailableEventResultsResponse + (*CreateDownloadResponse)(nil), // 59: proto.CreateDownloadResponse + (*Notebooks)(nil), // 60: proto.Notebooks + (*NotebookCell)(nil), // 61: proto.NotebookCell + (*NotebookFileUploadResponse)(nil), // 62: proto.NotebookFileUploadResponse } var file_api_proto_depIdxs = []int32{ 1, // 0: proto.ApprovalList.items:type_name -> proto.Approval @@ -1079,102 +1094,104 @@ var file_api_proto_depIdxs = []int32{ 19, // 14: proto.API.GetUserUITraits:input_type -> google.protobuf.Empty 20, // 15: proto.API.SetGUIOptions:input_type -> proto.SetGUIOptionsRequest 19, // 16: proto.API.GetUsers:input_type -> google.protobuf.Empty - 21, // 17: proto.API.VFSListDirectory:input_type -> proto.VFSListRequest - 3, // 18: proto.API.VFSRefreshDirectory:input_type -> proto.VFSRefreshDirectoryRequest - 21, // 19: proto.API.VFSStatDirectory:input_type -> proto.VFSListRequest - 22, // 20: proto.API.VFSStatDownload:input_type -> proto.VFSStatDownloadRequest - 12, // 21: proto.API.GetTable:input_type -> proto.GetTableRequest - 23, // 22: proto.API.CollectArtifact:input_type -> proto.ArtifactCollectorArgs - 18, // 23: proto.API.CancelFlow:input_type -> proto.ApiFlowRequest - 18, // 24: proto.API.ArchiveFlow:input_type -> proto.ApiFlowRequest - 18, // 25: proto.API.GetFlowDetails:input_type -> proto.ApiFlowRequest - 18, // 26: proto.API.GetFlowRequests:input_type -> proto.ApiFlowRequest - 19, // 27: proto.API.GetKeywordCompletions:input_type -> google.protobuf.Empty - 24, // 28: proto.API.GetArtifacts:input_type -> proto.GetArtifactsRequest - 25, // 29: proto.API.GetArtifactFile:input_type -> proto.GetArtifactRequest - 26, // 30: proto.API.SetArtifactFile:input_type -> proto.SetArtifactRequest - 4, // 31: proto.API.LoadArtifactPack:input_type -> proto.VFSFileBuffer - 27, // 32: proto.API.GetToolInfo:input_type -> proto.Tool - 27, // 33: proto.API.SetToolInfo:input_type -> proto.Tool - 28, // 34: proto.API.GetReport:input_type -> proto.GetReportRequest - 19, // 35: proto.API.GetServerMonitoringState:input_type -> google.protobuf.Empty - 23, // 36: proto.API.SetServerMonitoringState:input_type -> proto.ArtifactCollectorArgs - 19, // 37: proto.API.GetClientMonitoringState:input_type -> google.protobuf.Empty - 29, // 38: proto.API.SetClientMonitoringState:input_type -> proto.ClientEventTable - 30, // 39: proto.API.ListAvailableEventResults:input_type -> proto.ListAvailableEventResultsRequest - 31, // 40: proto.API.CreateDownloadFile:input_type -> proto.CreateDownloadRequest - 32, // 41: proto.API.GetNotebooks:input_type -> proto.NotebookCellRequest - 33, // 42: proto.API.NewNotebook:input_type -> proto.NotebookMetadata - 33, // 43: proto.API.UpdateNotebook:input_type -> proto.NotebookMetadata - 32, // 44: proto.API.NewNotebookCell:input_type -> proto.NotebookCellRequest - 32, // 45: proto.API.GetNotebookCell:input_type -> proto.NotebookCellRequest - 32, // 46: proto.API.UpdateNotebookCell:input_type -> proto.NotebookCellRequest - 32, // 47: proto.API.CancelNotebookCell:input_type -> proto.NotebookCellRequest - 34, // 48: proto.API.CreateNotebookDownloadFile:input_type -> proto.NotebookExportRequest - 35, // 49: proto.API.UploadNotebookAttachment:input_type -> proto.NotebookFileUploadRequest - 34, // 50: proto.API.ExportNotebook:input_type -> proto.NotebookExportRequest - 4, // 51: proto.API.VFSGetBuffer:input_type -> proto.VFSFileBuffer - 36, // 52: proto.API.Query:input_type -> proto.VQLCollectorArgs - 6, // 53: proto.API.WatchEvent:input_type -> proto.EventRequest - 8, // 54: proto.API.PushEvents:input_type -> proto.PushEventRequest - 37, // 55: proto.API.WriteEvent:input_type -> proto.VQLResponse - 0, // 56: proto.API.CreateHunt:output_type -> proto.StartFlowResponse - 38, // 57: proto.API.ListHunts:output_type -> proto.ListHuntsResponse - 9, // 58: proto.API.GetHunt:output_type -> proto.Hunt - 19, // 59: proto.API.ModifyHunt:output_type -> google.protobuf.Empty - 39, // 60: proto.API.GetHuntFlows:output_type -> proto.GetTableResponse - 39, // 61: proto.API.GetHuntResults:output_type -> proto.GetTableResponse - 19, // 62: proto.API.NotifyClients:output_type -> google.protobuf.Empty - 40, // 63: proto.API.LabelClients:output_type -> proto.APIResponse - 41, // 64: proto.API.ListClients:output_type -> proto.SearchClientsResponse - 42, // 65: proto.API.GetClient:output_type -> proto.ApiClient - 17, // 66: proto.API.GetClientMetadata:output_type -> proto.ClientMetadata - 19, // 67: proto.API.SetClientMetadata:output_type -> google.protobuf.Empty - 43, // 68: proto.API.GetClientFlows:output_type -> proto.ApiFlowResponse - 44, // 69: proto.API.GetUserUITraits:output_type -> proto.ApiGrrUser - 19, // 70: proto.API.SetGUIOptions:output_type -> google.protobuf.Empty - 45, // 71: proto.API.GetUsers:output_type -> proto.Users - 46, // 72: proto.API.VFSListDirectory:output_type -> proto.VFSListResponse - 47, // 73: proto.API.VFSRefreshDirectory:output_type -> proto.ArtifactCollectorResponse - 46, // 74: proto.API.VFSStatDirectory:output_type -> proto.VFSListResponse - 48, // 75: proto.API.VFSStatDownload:output_type -> proto.VFSDownloadInfo - 39, // 76: proto.API.GetTable:output_type -> proto.GetTableResponse - 47, // 77: proto.API.CollectArtifact:output_type -> proto.ArtifactCollectorResponse - 0, // 78: proto.API.CancelFlow:output_type -> proto.StartFlowResponse - 0, // 79: proto.API.ArchiveFlow:output_type -> proto.StartFlowResponse - 49, // 80: proto.API.GetFlowDetails:output_type -> proto.FlowDetails - 50, // 81: proto.API.GetFlowRequests:output_type -> proto.ApiFlowRequestDetails - 51, // 82: proto.API.GetKeywordCompletions:output_type -> proto.KeywordCompletions - 52, // 83: proto.API.GetArtifacts:output_type -> proto.ArtifactDescriptors - 53, // 84: proto.API.GetArtifactFile:output_type -> proto.GetArtifactResponse - 40, // 85: proto.API.SetArtifactFile:output_type -> proto.APIResponse - 54, // 86: proto.API.LoadArtifactPack:output_type -> proto.LoadArtifactPackResponse - 27, // 87: proto.API.GetToolInfo:output_type -> proto.Tool - 27, // 88: proto.API.SetToolInfo:output_type -> proto.Tool - 55, // 89: proto.API.GetReport:output_type -> proto.GetReportResponse - 23, // 90: proto.API.GetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs - 23, // 91: proto.API.SetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs - 29, // 92: proto.API.GetClientMonitoringState:output_type -> proto.ClientEventTable - 19, // 93: proto.API.SetClientMonitoringState:output_type -> google.protobuf.Empty - 56, // 94: proto.API.ListAvailableEventResults:output_type -> proto.ListAvailableEventResultsResponse - 57, // 95: proto.API.CreateDownloadFile:output_type -> proto.CreateDownloadResponse - 58, // 96: proto.API.GetNotebooks:output_type -> proto.Notebooks - 33, // 97: proto.API.NewNotebook:output_type -> proto.NotebookMetadata - 33, // 98: proto.API.UpdateNotebook:output_type -> proto.NotebookMetadata - 33, // 99: proto.API.NewNotebookCell:output_type -> proto.NotebookMetadata - 59, // 100: proto.API.GetNotebookCell:output_type -> proto.NotebookCell - 59, // 101: proto.API.UpdateNotebookCell:output_type -> proto.NotebookCell - 19, // 102: proto.API.CancelNotebookCell:output_type -> google.protobuf.Empty - 19, // 103: proto.API.CreateNotebookDownloadFile:output_type -> google.protobuf.Empty - 60, // 104: proto.API.UploadNotebookAttachment:output_type -> proto.NotebookFileUploadResponse - 19, // 105: proto.API.ExportNotebook:output_type -> google.protobuf.Empty - 4, // 106: proto.API.VFSGetBuffer:output_type -> proto.VFSFileBuffer - 37, // 107: proto.API.Query:output_type -> proto.VQLResponse - 7, // 108: proto.API.WatchEvent:output_type -> proto.EventResponse - 19, // 109: proto.API.PushEvents:output_type -> google.protobuf.Empty - 19, // 110: proto.API.WriteEvent:output_type -> google.protobuf.Empty - 56, // [56:111] is the sub-list for method output_type - 1, // [1:56] is the sub-list for method input_type + 21, // 17: proto.API.GetUserFavorites:input_type -> proto.Favorite + 22, // 18: proto.API.VFSListDirectory:input_type -> proto.VFSListRequest + 3, // 19: proto.API.VFSRefreshDirectory:input_type -> proto.VFSRefreshDirectoryRequest + 22, // 20: proto.API.VFSStatDirectory:input_type -> proto.VFSListRequest + 23, // 21: proto.API.VFSStatDownload:input_type -> proto.VFSStatDownloadRequest + 12, // 22: proto.API.GetTable:input_type -> proto.GetTableRequest + 24, // 23: proto.API.CollectArtifact:input_type -> proto.ArtifactCollectorArgs + 18, // 24: proto.API.CancelFlow:input_type -> proto.ApiFlowRequest + 18, // 25: proto.API.ArchiveFlow:input_type -> proto.ApiFlowRequest + 18, // 26: proto.API.GetFlowDetails:input_type -> proto.ApiFlowRequest + 18, // 27: proto.API.GetFlowRequests:input_type -> proto.ApiFlowRequest + 19, // 28: proto.API.GetKeywordCompletions:input_type -> google.protobuf.Empty + 25, // 29: proto.API.GetArtifacts:input_type -> proto.GetArtifactsRequest + 26, // 30: proto.API.GetArtifactFile:input_type -> proto.GetArtifactRequest + 27, // 31: proto.API.SetArtifactFile:input_type -> proto.SetArtifactRequest + 4, // 32: proto.API.LoadArtifactPack:input_type -> proto.VFSFileBuffer + 28, // 33: proto.API.GetToolInfo:input_type -> proto.Tool + 28, // 34: proto.API.SetToolInfo:input_type -> proto.Tool + 29, // 35: proto.API.GetReport:input_type -> proto.GetReportRequest + 19, // 36: proto.API.GetServerMonitoringState:input_type -> google.protobuf.Empty + 24, // 37: proto.API.SetServerMonitoringState:input_type -> proto.ArtifactCollectorArgs + 19, // 38: proto.API.GetClientMonitoringState:input_type -> google.protobuf.Empty + 30, // 39: proto.API.SetClientMonitoringState:input_type -> proto.ClientEventTable + 31, // 40: proto.API.ListAvailableEventResults:input_type -> proto.ListAvailableEventResultsRequest + 32, // 41: proto.API.CreateDownloadFile:input_type -> proto.CreateDownloadRequest + 33, // 42: proto.API.GetNotebooks:input_type -> proto.NotebookCellRequest + 34, // 43: proto.API.NewNotebook:input_type -> proto.NotebookMetadata + 34, // 44: proto.API.UpdateNotebook:input_type -> proto.NotebookMetadata + 33, // 45: proto.API.NewNotebookCell:input_type -> proto.NotebookCellRequest + 33, // 46: proto.API.GetNotebookCell:input_type -> proto.NotebookCellRequest + 33, // 47: proto.API.UpdateNotebookCell:input_type -> proto.NotebookCellRequest + 33, // 48: proto.API.CancelNotebookCell:input_type -> proto.NotebookCellRequest + 35, // 49: proto.API.CreateNotebookDownloadFile:input_type -> proto.NotebookExportRequest + 36, // 50: proto.API.UploadNotebookAttachment:input_type -> proto.NotebookFileUploadRequest + 35, // 51: proto.API.ExportNotebook:input_type -> proto.NotebookExportRequest + 4, // 52: proto.API.VFSGetBuffer:input_type -> proto.VFSFileBuffer + 37, // 53: proto.API.Query:input_type -> proto.VQLCollectorArgs + 6, // 54: proto.API.WatchEvent:input_type -> proto.EventRequest + 8, // 55: proto.API.PushEvents:input_type -> proto.PushEventRequest + 38, // 56: proto.API.WriteEvent:input_type -> proto.VQLResponse + 0, // 57: proto.API.CreateHunt:output_type -> proto.StartFlowResponse + 39, // 58: proto.API.ListHunts:output_type -> proto.ListHuntsResponse + 9, // 59: proto.API.GetHunt:output_type -> proto.Hunt + 19, // 60: proto.API.ModifyHunt:output_type -> google.protobuf.Empty + 40, // 61: proto.API.GetHuntFlows:output_type -> proto.GetTableResponse + 40, // 62: proto.API.GetHuntResults:output_type -> proto.GetTableResponse + 19, // 63: proto.API.NotifyClients:output_type -> google.protobuf.Empty + 41, // 64: proto.API.LabelClients:output_type -> proto.APIResponse + 42, // 65: proto.API.ListClients:output_type -> proto.SearchClientsResponse + 43, // 66: proto.API.GetClient:output_type -> proto.ApiClient + 17, // 67: proto.API.GetClientMetadata:output_type -> proto.ClientMetadata + 19, // 68: proto.API.SetClientMetadata:output_type -> google.protobuf.Empty + 44, // 69: proto.API.GetClientFlows:output_type -> proto.ApiFlowResponse + 45, // 70: proto.API.GetUserUITraits:output_type -> proto.ApiGrrUser + 19, // 71: proto.API.SetGUIOptions:output_type -> google.protobuf.Empty + 46, // 72: proto.API.GetUsers:output_type -> proto.Users + 47, // 73: proto.API.GetUserFavorites:output_type -> proto.Favorites + 48, // 74: proto.API.VFSListDirectory:output_type -> proto.VFSListResponse + 49, // 75: proto.API.VFSRefreshDirectory:output_type -> proto.ArtifactCollectorResponse + 48, // 76: proto.API.VFSStatDirectory:output_type -> proto.VFSListResponse + 50, // 77: proto.API.VFSStatDownload:output_type -> proto.VFSDownloadInfo + 40, // 78: proto.API.GetTable:output_type -> proto.GetTableResponse + 49, // 79: proto.API.CollectArtifact:output_type -> proto.ArtifactCollectorResponse + 0, // 80: proto.API.CancelFlow:output_type -> proto.StartFlowResponse + 0, // 81: proto.API.ArchiveFlow:output_type -> proto.StartFlowResponse + 51, // 82: proto.API.GetFlowDetails:output_type -> proto.FlowDetails + 52, // 83: proto.API.GetFlowRequests:output_type -> proto.ApiFlowRequestDetails + 53, // 84: proto.API.GetKeywordCompletions:output_type -> proto.KeywordCompletions + 54, // 85: proto.API.GetArtifacts:output_type -> proto.ArtifactDescriptors + 55, // 86: proto.API.GetArtifactFile:output_type -> proto.GetArtifactResponse + 41, // 87: proto.API.SetArtifactFile:output_type -> proto.APIResponse + 56, // 88: proto.API.LoadArtifactPack:output_type -> proto.LoadArtifactPackResponse + 28, // 89: proto.API.GetToolInfo:output_type -> proto.Tool + 28, // 90: proto.API.SetToolInfo:output_type -> proto.Tool + 57, // 91: proto.API.GetReport:output_type -> proto.GetReportResponse + 24, // 92: proto.API.GetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs + 24, // 93: proto.API.SetServerMonitoringState:output_type -> proto.ArtifactCollectorArgs + 30, // 94: proto.API.GetClientMonitoringState:output_type -> proto.ClientEventTable + 19, // 95: proto.API.SetClientMonitoringState:output_type -> google.protobuf.Empty + 58, // 96: proto.API.ListAvailableEventResults:output_type -> proto.ListAvailableEventResultsResponse + 59, // 97: proto.API.CreateDownloadFile:output_type -> proto.CreateDownloadResponse + 60, // 98: proto.API.GetNotebooks:output_type -> proto.Notebooks + 34, // 99: proto.API.NewNotebook:output_type -> proto.NotebookMetadata + 34, // 100: proto.API.UpdateNotebook:output_type -> proto.NotebookMetadata + 34, // 101: proto.API.NewNotebookCell:output_type -> proto.NotebookMetadata + 61, // 102: proto.API.GetNotebookCell:output_type -> proto.NotebookCell + 61, // 103: proto.API.UpdateNotebookCell:output_type -> proto.NotebookCell + 19, // 104: proto.API.CancelNotebookCell:output_type -> google.protobuf.Empty + 19, // 105: proto.API.CreateNotebookDownloadFile:output_type -> google.protobuf.Empty + 62, // 106: proto.API.UploadNotebookAttachment:output_type -> proto.NotebookFileUploadResponse + 19, // 107: proto.API.ExportNotebook:output_type -> google.protobuf.Empty + 4, // 108: proto.API.VFSGetBuffer:output_type -> proto.VFSFileBuffer + 38, // 109: proto.API.Query:output_type -> proto.VQLResponse + 7, // 110: proto.API.WatchEvent:output_type -> proto.EventResponse + 19, // 111: proto.API.PushEvents:output_type -> google.protobuf.Empty + 19, // 112: proto.API.WriteEvent:output_type -> google.protobuf.Empty + 57, // [57:113] is the sub-list for method output_type + 1, // [1:57] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name 1, // [1:1] is the sub-list for extension extendee 0, // [0:1] is the sub-list for field type_name @@ -1194,6 +1211,7 @@ func file_api_proto_init() { file_csv_proto_init() file_download_proto_init() file_completions_proto_init() + file_vfs_api_proto_init() if !protoimpl.UnsafeEnabled { file_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StartFlowResponse); i { diff --git a/api/proto/api.pb.gw.go b/api/proto/api.pb.gw.go index 2c3fad84faa..a82389bccb9 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_5 "www.velocidex.com/golang/velociraptor/artifacts/proto" - proto_3 "www.velocidex.com/golang/velociraptor/flows/proto" + proto_6 "www.velocidex.com/golang/velociraptor/artifacts/proto" + proto_0 "www.velocidex.com/golang/velociraptor/flows/proto" ) // Suppress "imported and not used" errors @@ -734,12 +734,48 @@ func local_request_API_GetUsers_0(ctx context.Context, marshaler runtime.Marshal } +var ( + filter_API_GetUserFavorites_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_API_GetUserFavorites_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Favorite + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_API_GetUserFavorites_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetUserFavorites(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_API_GetUserFavorites_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq Favorite + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_API_GetUserFavorites_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetUserFavorites(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_API_VFSListDirectory_0 = &utilities.DoubleArray{Encoding: map[string]int{"client_id": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} ) func request_API_VFSListDirectory_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_3.VFSListRequest + var protoReq VFSListRequest var metadata runtime.ServerMetadata var ( @@ -772,7 +808,7 @@ func request_API_VFSListDirectory_0(ctx context.Context, marshaler runtime.Marsh } func local_request_API_VFSListDirectory_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_3.VFSListRequest + var protoReq VFSListRequest var metadata runtime.ServerMetadata var ( @@ -843,7 +879,7 @@ var ( ) func request_API_VFSStatDirectory_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_3.VFSListRequest + var protoReq VFSListRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -859,7 +895,7 @@ func request_API_VFSStatDirectory_0(ctx context.Context, marshaler runtime.Marsh } func local_request_API_VFSStatDirectory_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_3.VFSListRequest + var protoReq VFSListRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -879,7 +915,7 @@ var ( ) func request_API_VFSStatDownload_0(ctx context.Context, marshaler runtime.Marshaler, client APIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_3.VFSStatDownloadRequest + var protoReq VFSStatDownloadRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -895,7 +931,7 @@ func request_API_VFSStatDownload_0(ctx context.Context, marshaler runtime.Marsha } func local_request_API_VFSStatDownload_0(ctx context.Context, marshaler runtime.Marshaler, server APIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq proto_3.VFSStatDownloadRequest + var protoReq VFSStatDownloadRequest var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -947,7 +983,7 @@ func local_request_API_GetTable_0(ctx context.Context, marshaler runtime.Marshal } 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_3.ArtifactCollectorArgs + var protoReq proto_0.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -964,7 +1000,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_3.ArtifactCollectorArgs + var protoReq proto_0.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1283,7 +1319,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_5.Tool + var protoReq proto_6.Tool var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1299,7 +1335,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_5.Tool + var protoReq proto_6.Tool var metadata runtime.ServerMetadata if err := req.ParseForm(); err != nil { @@ -1315,7 +1351,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_5.Tool + var protoReq proto_6.Tool var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1332,7 +1368,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_5.Tool + var protoReq proto_6.Tool var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1401,7 +1437,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_3.ArtifactCollectorArgs + var protoReq proto_0.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1418,7 +1454,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_3.ArtifactCollectorArgs + var protoReq proto_0.ArtifactCollectorArgs var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1453,7 +1489,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_3.ClientEventTable + var protoReq proto_0.ClientEventTable var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -1470,7 +1506,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_3.ClientEventTable + var protoReq proto_0.ClientEventTable var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -2295,6 +2331,29 @@ func RegisterAPIHandlerServer(ctx context.Context, mux *runtime.ServeMux, server }) + mux.Handle("GET", pattern_API_GetUserFavorites_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/proto.API/GetUserFavorites") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_API_GetUserFavorites_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_API_GetUserFavorites_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_API_VFSListDirectory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -3458,6 +3517,26 @@ func RegisterAPIHandlerClient(ctx context.Context, mux *runtime.ServeMux, client }) + mux.Handle("GET", pattern_API_GetUserFavorites_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/proto.API/GetUserFavorites") + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_API_GetUserFavorites_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_API_GetUserFavorites_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_API_VFSListDirectory_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -4176,6 +4255,8 @@ var ( pattern_API_GetUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "GetUsers"}, "")) + pattern_API_GetUserFavorites_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "GetUserFavorites"}, "")) + pattern_API_VFSListDirectory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "VFSListDirectory", "client_id"}, "")) pattern_API_VFSRefreshDirectory_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "VFSRefreshDirectory"}, "")) @@ -4280,6 +4361,8 @@ var ( forward_API_GetUsers_0 = runtime.ForwardResponseMessage + forward_API_GetUserFavorites_0 = runtime.ForwardResponseMessage + forward_API_VFSListDirectory_0 = runtime.ForwardResponseMessage forward_API_VFSRefreshDirectory_0 = runtime.ForwardResponseMessage diff --git a/api/proto/api.proto b/api/proto/api.proto index 9fc0a6293ea..89f1a922f85 100644 --- a/api/proto/api.proto +++ b/api/proto/api.proto @@ -18,6 +18,7 @@ import "users.proto"; import "csv.proto"; import "download.proto"; import "completions.proto"; +import "vfs_api.proto"; package proto; @@ -42,9 +43,10 @@ message VFSRefreshDirectoryRequest { label: HIDDEN, }]; - string vfs_path = 2 [(sem_type) = { - description: "The VFS Path to list files in .", - }]; + // Deprecated + string XXXXvfs_path = 2; + + repeated string vfs_components = 4; uint64 depth = 3 [(sem_type) = { description: "Depth of directory refresh", @@ -53,13 +55,10 @@ message VFSRefreshDirectoryRequest { message VFSFileBuffer { string client_id = 1; - string vfs_path = 2 [(sem_type) = { - description: "The VFS Path to list files in .", - }]; - uint64 offset = 3; uint32 length = 4; bytes data = 5; + repeated string components = 6; } @@ -207,6 +206,12 @@ service API { }; } + rpc GetUserFavorites(Favorite) returns(Favorites) { + option (google.api.http) = { + get: "/api/v1/GetUserFavorites", + }; + } + // VFS rpc VFSListDirectory(VFSListRequest) returns (VFSListResponse) { option (google.api.http) = { diff --git a/api/proto/api_grpc.pb.go b/api/proto/api_grpc.pb.go index 5c1aa662c59..cd0209a6fd4 100644 --- a/api/proto/api_grpc.pb.go +++ b/api/proto/api_grpc.pb.go @@ -42,11 +42,12 @@ type APIClient interface { SetGUIOptions(ctx context.Context, in *SetGUIOptionsRequest, opts ...grpc.CallOption) (*empty.Empty, error) // List all the GUI users known on this server. GetUsers(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*Users, error) + GetUserFavorites(ctx context.Context, in *Favorite, opts ...grpc.CallOption) (*Favorites, error) // VFS - VFSListDirectory(ctx context.Context, in *proto.VFSListRequest, opts ...grpc.CallOption) (*proto.VFSListResponse, error) + VFSListDirectory(ctx context.Context, in *VFSListRequest, opts ...grpc.CallOption) (*VFSListResponse, error) VFSRefreshDirectory(ctx context.Context, in *VFSRefreshDirectoryRequest, opts ...grpc.CallOption) (*proto.ArtifactCollectorResponse, error) - VFSStatDirectory(ctx context.Context, in *proto.VFSListRequest, opts ...grpc.CallOption) (*proto.VFSListResponse, error) - VFSStatDownload(ctx context.Context, in *proto.VFSStatDownloadRequest, opts ...grpc.CallOption) (*proto.VFSDownloadInfo, error) + VFSStatDirectory(ctx context.Context, in *VFSListRequest, opts ...grpc.CallOption) (*VFSListResponse, error) + VFSStatDownload(ctx context.Context, in *VFSStatDownloadRequest, opts ...grpc.CallOption) (*proto.VFSDownloadInfo, error) GetTable(ctx context.Context, in *GetTableRequest, opts ...grpc.CallOption) (*GetTableResponse, error) // Flows CollectArtifact(ctx context.Context, in *proto.ArtifactCollectorArgs, opts ...grpc.CallOption) (*proto.ArtifactCollectorResponse, error) @@ -255,8 +256,17 @@ func (c *aPIClient) GetUsers(ctx context.Context, in *empty.Empty, opts ...grpc. return out, nil } -func (c *aPIClient) VFSListDirectory(ctx context.Context, in *proto.VFSListRequest, opts ...grpc.CallOption) (*proto.VFSListResponse, error) { - out := new(proto.VFSListResponse) +func (c *aPIClient) GetUserFavorites(ctx context.Context, in *Favorite, opts ...grpc.CallOption) (*Favorites, error) { + out := new(Favorites) + err := c.cc.Invoke(ctx, "/proto.API/GetUserFavorites", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aPIClient) VFSListDirectory(ctx context.Context, in *VFSListRequest, opts ...grpc.CallOption) (*VFSListResponse, error) { + out := new(VFSListResponse) err := c.cc.Invoke(ctx, "/proto.API/VFSListDirectory", in, out, opts...) if err != nil { return nil, err @@ -273,8 +283,8 @@ func (c *aPIClient) VFSRefreshDirectory(ctx context.Context, in *VFSRefreshDirec return out, nil } -func (c *aPIClient) VFSStatDirectory(ctx context.Context, in *proto.VFSListRequest, opts ...grpc.CallOption) (*proto.VFSListResponse, error) { - out := new(proto.VFSListResponse) +func (c *aPIClient) VFSStatDirectory(ctx context.Context, in *VFSListRequest, opts ...grpc.CallOption) (*VFSListResponse, error) { + out := new(VFSListResponse) err := c.cc.Invoke(ctx, "/proto.API/VFSStatDirectory", in, out, opts...) if err != nil { return nil, err @@ -282,7 +292,7 @@ func (c *aPIClient) VFSStatDirectory(ctx context.Context, in *proto.VFSListReque return out, nil } -func (c *aPIClient) VFSStatDownload(ctx context.Context, in *proto.VFSStatDownloadRequest, opts ...grpc.CallOption) (*proto.VFSDownloadInfo, error) { +func (c *aPIClient) VFSStatDownload(ctx context.Context, in *VFSStatDownloadRequest, opts ...grpc.CallOption) (*proto.VFSDownloadInfo, error) { out := new(proto.VFSDownloadInfo) err := c.cc.Invoke(ctx, "/proto.API/VFSStatDownload", in, out, opts...) if err != nil { @@ -676,11 +686,12 @@ type APIServer interface { SetGUIOptions(context.Context, *SetGUIOptionsRequest) (*empty.Empty, error) // List all the GUI users known on this server. GetUsers(context.Context, *empty.Empty) (*Users, error) + GetUserFavorites(context.Context, *Favorite) (*Favorites, error) // VFS - VFSListDirectory(context.Context, *proto.VFSListRequest) (*proto.VFSListResponse, error) + VFSListDirectory(context.Context, *VFSListRequest) (*VFSListResponse, error) VFSRefreshDirectory(context.Context, *VFSRefreshDirectoryRequest) (*proto.ArtifactCollectorResponse, error) - VFSStatDirectory(context.Context, *proto.VFSListRequest) (*proto.VFSListResponse, error) - VFSStatDownload(context.Context, *proto.VFSStatDownloadRequest) (*proto.VFSDownloadInfo, error) + VFSStatDirectory(context.Context, *VFSListRequest) (*VFSListResponse, error) + VFSStatDownload(context.Context, *VFSStatDownloadRequest) (*proto.VFSDownloadInfo, error) GetTable(context.Context, *GetTableRequest) (*GetTableResponse, error) // Flows CollectArtifact(context.Context, *proto.ArtifactCollectorArgs) (*proto.ArtifactCollectorResponse, error) @@ -790,16 +801,19 @@ func (UnimplementedAPIServer) SetGUIOptions(context.Context, *SetGUIOptionsReque func (UnimplementedAPIServer) GetUsers(context.Context, *empty.Empty) (*Users, error) { return nil, status.Errorf(codes.Unimplemented, "method GetUsers not implemented") } -func (UnimplementedAPIServer) VFSListDirectory(context.Context, *proto.VFSListRequest) (*proto.VFSListResponse, error) { +func (UnimplementedAPIServer) GetUserFavorites(context.Context, *Favorite) (*Favorites, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUserFavorites not implemented") +} +func (UnimplementedAPIServer) VFSListDirectory(context.Context, *VFSListRequest) (*VFSListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method VFSListDirectory not implemented") } func (UnimplementedAPIServer) VFSRefreshDirectory(context.Context, *VFSRefreshDirectoryRequest) (*proto.ArtifactCollectorResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method VFSRefreshDirectory not implemented") } -func (UnimplementedAPIServer) VFSStatDirectory(context.Context, *proto.VFSListRequest) (*proto.VFSListResponse, error) { +func (UnimplementedAPIServer) VFSStatDirectory(context.Context, *VFSListRequest) (*VFSListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method VFSStatDirectory not implemented") } -func (UnimplementedAPIServer) VFSStatDownload(context.Context, *proto.VFSStatDownloadRequest) (*proto.VFSDownloadInfo, error) { +func (UnimplementedAPIServer) VFSStatDownload(context.Context, *VFSStatDownloadRequest) (*proto.VFSDownloadInfo, error) { return nil, status.Errorf(codes.Unimplemented, "method VFSStatDownload not implemented") } func (UnimplementedAPIServer) GetTable(context.Context, *GetTableRequest) (*GetTableResponse, error) { @@ -1208,8 +1222,26 @@ func _API_GetUsers_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _API_GetUserFavorites_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Favorite) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(APIServer).GetUserFavorites(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.API/GetUserFavorites", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(APIServer).GetUserFavorites(ctx, req.(*Favorite)) + } + return interceptor(ctx, in, info, handler) +} + func _API_VFSListDirectory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(proto.VFSListRequest) + in := new(VFSListRequest) if err := dec(in); err != nil { return nil, err } @@ -1221,7 +1253,7 @@ func _API_VFSListDirectory_Handler(srv interface{}, ctx context.Context, dec fun FullMethod: "/proto.API/VFSListDirectory", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(APIServer).VFSListDirectory(ctx, req.(*proto.VFSListRequest)) + return srv.(APIServer).VFSListDirectory(ctx, req.(*VFSListRequest)) } return interceptor(ctx, in, info, handler) } @@ -1245,7 +1277,7 @@ func _API_VFSRefreshDirectory_Handler(srv interface{}, ctx context.Context, dec } func _API_VFSStatDirectory_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(proto.VFSListRequest) + in := new(VFSListRequest) if err := dec(in); err != nil { return nil, err } @@ -1257,13 +1289,13 @@ func _API_VFSStatDirectory_Handler(srv interface{}, ctx context.Context, dec fun FullMethod: "/proto.API/VFSStatDirectory", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(APIServer).VFSStatDirectory(ctx, req.(*proto.VFSListRequest)) + return srv.(APIServer).VFSStatDirectory(ctx, req.(*VFSListRequest)) } return interceptor(ctx, in, info, handler) } func _API_VFSStatDownload_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(proto.VFSStatDownloadRequest) + in := new(VFSStatDownloadRequest) if err := dec(in); err != nil { return nil, err } @@ -1275,7 +1307,7 @@ func _API_VFSStatDownload_Handler(srv interface{}, ctx context.Context, dec func FullMethod: "/proto.API/VFSStatDownload", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(APIServer).VFSStatDownload(ctx, req.(*proto.VFSStatDownloadRequest)) + return srv.(APIServer).VFSStatDownload(ctx, req.(*VFSStatDownloadRequest)) } return interceptor(ctx, in, info, handler) } @@ -1987,6 +2019,10 @@ var API_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetUsers", Handler: _API_GetUsers_Handler, }, + { + MethodName: "GetUserFavorites", + Handler: _API_GetUserFavorites_Handler, + }, { MethodName: "VFSListDirectory", Handler: _API_VFSListDirectory_Handler, diff --git a/api/proto/users.pb.go b/api/proto/users.pb.go index 06552e9325b..0dcbc66538f 100644 --- a/api/proto/users.pb.go +++ b/api/proto/users.pb.go @@ -12,6 +12,7 @@ import ( reflect "reflect" sync "sync" proto "www.velocidex.com/golang/velociraptor/acls/proto" + proto1 "www.velocidex.com/golang/velociraptor/flows/proto" _ "www.velocidex.com/golang/velociraptor/proto" ) @@ -966,6 +967,125 @@ func (x *Users) GetUsers() []*VelociraptorUser { return nil } +// Store favorite collections (essential preset collection specs) +type Favorite struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Spec []*proto1.ArtifactSpec `protobuf:"bytes,3,rep,name=spec,proto3" json:"spec,omitempty"` + Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` +} + +func (x *Favorite) Reset() { + *x = Favorite{} + if protoimpl.UnsafeEnabled { + mi := &file_users_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Favorite) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Favorite) ProtoMessage() {} + +func (x *Favorite) ProtoReflect() protoreflect.Message { + mi := &file_users_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Favorite.ProtoReflect.Descriptor instead. +func (*Favorite) Descriptor() ([]byte, []int) { + return file_users_proto_rawDescGZIP(), []int{11} +} + +func (x *Favorite) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Favorite) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Favorite) GetSpec() []*proto1.ArtifactSpec { + if x != nil { + return x.Spec + } + return nil +} + +func (x *Favorite) GetType() string { + if x != nil { + return x.Type + } + return "" +} + +type Favorites struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*Favorite `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *Favorites) Reset() { + *x = Favorites{} + if protoimpl.UnsafeEnabled { + mi := &file_users_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Favorites) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Favorites) ProtoMessage() {} + +func (x *Favorites) ProtoReflect() protoreflect.Message { + mi := &file_users_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Favorites.ProtoReflect.Descriptor instead. +func (*Favorites) Descriptor() ([]byte, []int) { + return file_users_proto_rawDescGZIP(), []int{12} +} + +func (x *Favorites) GetItems() []*Favorite { + if x != nil { + return x.Items + } + return nil +} + var File_users_proto protoreflect.FileDescriptor var file_users_proto_rawDesc = []byte{ @@ -973,183 +1093,197 @@ var file_users_proto_rawDesc = []byte{ 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, 0x1a, 0x14, 0x61, 0x63, 0x6c, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x63, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x22, 0xf9, 0x03, 0x0a, 0x10, 0x56, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, - 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x14, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x0e, 0x12, 0x0c, 0x54, 0x68, 0x65, - 0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x49, 0x0a, 0x0d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x24, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1e, 0x12, 0x1c, - 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2e, 0x52, 0x0c, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x73, 0x61, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0c, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x53, 0x61, 0x6c, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, - 0x25, 0x0a, 0x0e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x65, 0x6d, 0x61, 0x69, - 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x72, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, - 0x6e, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x42, 0x55, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, - 0x4f, 0x12, 0x4d, 0x41, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x75, - 0x73, 0x65, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x47, 0x55, 0x49, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, - 0x20, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x6f, 0x72, 0x20, 0x68, 0x75, 0x6e, 0x74, 0x73, 0x2e, - 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x49, 0x0a, 0x06, 0x6c, 0x6f, - 0x63, 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x42, 0x31, 0xe2, 0xfc, 0xe3, 0xc4, - 0x01, 0x2b, 0x12, 0x29, 0x49, 0x66, 0x20, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, - 0x73, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x6f, 0x67, 0x20, 0x69, 0x6e, 0x2e, 0x52, 0x06, 0x6c, - 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, 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, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x8e, 0x02, 0x0a, - 0x0b, 0x47, 0x55, 0x49, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x04, - 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x47, 0x55, 0x49, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x55, - 0x49, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x1c, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x16, 0x12, 0x14, 0x55, - 0x73, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0x6d, 0x6f, - 0x64, 0x65, 0x2e, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x58, 0x0a, 0x0b, 0x63, 0x61, 0x6e, - 0x61, 0x72, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x42, 0x37, - 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x31, 0x12, 0x2f, 0x49, 0x66, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, - 0x20, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x20, 0x74, - 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x62, 0x65, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x61, - 0x6e, 0x61, 0x72, 0x69, 0x65, 0x64, 0x2e, 0x52, 0x0a, 0x63, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x4d, - 0x6f, 0x64, 0x65, 0x22, 0x2c, 0x0a, 0x06, 0x55, 0x49, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x09, 0x0a, - 0x05, 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x44, 0x56, 0x41, - 0x4e, 0x43, 0x45, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, - 0x02, 0x3a, 0x2a, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0x24, 0x0a, 0x22, 0x55, 0x73, 0x65, 0x72, 0x20, - 0x47, 0x55, 0x49, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x61, 0x6e, 0x64, - 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x22, 0x2e, 0x0a, - 0x06, 0x55, 0x49, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, - 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0xf4, 0x01, - 0x0a, 0x19, 0x41, 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x66, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x50, + 0x1a, 0x24, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf9, 0x03, 0x0a, 0x10, 0x56, 0x65, 0x6c, 0x6f, 0x63, + 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x14, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, + 0x0e, 0x12, 0x0c, 0x54, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x0d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x24, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x1e, 0x12, 0x1c, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20, 0x68, 0x61, 0x73, + 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x2e, 0x52, 0x0c, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x48, 0x61, 0x73, 0x68, + 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x73, 0x61, 0x6c, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, + 0x64, 0x53, 0x61, 0x6c, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x69, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x76, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x72, 0x0a, 0x09, + 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x42, + 0x55, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x4f, 0x12, 0x4d, 0x41, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, + 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x75, 0x73, + 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x55, 0x49, 0x20, 0x62, 0x75, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, + 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x20, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x20, 0x6f, 0x72, 0x20, + 0x68, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, + 0x12, 0x49, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, + 0x42, 0x31, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2b, 0x12, 0x29, 0x49, 0x66, 0x20, 0x73, 0x65, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x6f, 0x67, 0x20, + 0x69, 0x6e, 0x2e, 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x09, 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, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x75, 0x73, 0x69, 0x6e, 0x67, - 0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x18, 0x13, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x61, - 0x75, 0x74, 0x68, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x23, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, - 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x55, 0x49, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x12, 0x14, 0x0a, - 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x68, - 0x65, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x69, 0x5f, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, - 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x69, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x22, 0xaf, 0x03, 0x0a, 0x0a, 0x41, 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, - 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x17, 0x12, 0x15, 0x54, - 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, - 0x73, 0x65, 0x72, 0x2e, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x49, - 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x55, 0x49, 0x53, 0x65, 0x74, 0x74, - 0x69, 0x6e, 0x67, 0x73, 0x42, 0x19, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x13, 0x12, 0x11, 0x55, 0x73, - 0x65, 0x72, 0x20, 0x55, 0x49, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, - 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x94, 0x01, 0x0a, 0x10, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, - 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x42, 0x47, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x41, 0x12, 0x3f, - 0x55, 0x73, 0x65, 0x72, 0x27, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, - 0x20, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x20, 0x28, 0x77, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, - 0x65, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, - 0x20, 0x64, 0x6f, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x55, 0x49, 0x29, 0x2e, 0x52, - 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, - 0x12, 0x37, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x47, - 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, 0x4b, 0x0a, 0x08, 0x55, 0x73, 0x65, - 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, - 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, 0x10, - 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, - 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x22, 0x2d, 0x0a, 0x15, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfa, 0x06, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, - 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x10, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, 0x13, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, - 0x0d, 0x0a, 0x0b, 0x52, 0x44, 0x46, 0x44, 0x61, 0x74, 0x65, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x22, 0xb8, 0x04, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x54, 0x45, - 0x52, 0x52, 0x4f, 0x47, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x22, 0x0a, 0x1e, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, - 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x20, - 0x0a, 0x1c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, - 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x03, - 0x12, 0x24, 0x0a, 0x20, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x4f, 0x4e, 0x5f, 0x4a, 0x4f, - 0x42, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, - 0x53, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, - 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x47, - 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x48, 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x47, - 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x06, 0x12, 0x22, 0x0a, 0x1e, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x43, 0x52, 0x4f, 0x4e, 0x5f, 0x4a, 0x4f, 0x42, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, - 0x41, 0x4c, 0x5f, 0x47, 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x43, 0x4f, - 0x4c, 0x4c, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x08, 0x12, 0x23, 0x0a, 0x1f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x43, 0x4f, 0x4c, 0x4c, 0x45, - 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x09, 0x12, 0x15, - 0x0a, 0x11, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x4e, 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x50, - 0x50, 0x45, 0x44, 0x10, 0x0a, 0x12, 0x1f, 0x0a, 0x1b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, - 0x4c, 0x45, 0x5f, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, - 0x41, 0x54, 0x45, 0x44, 0x10, 0x0b, 0x12, 0x27, 0x0a, 0x23, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, - 0x49, 0x4c, 0x45, 0x5f, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, - 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x0c, 0x12, - 0x1b, 0x0a, 0x17, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x52, 0x55, 0x4e, - 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x18, 0x0a, 0x14, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4c, 0x4f, 0x57, 0x5f, 0x52, 0x55, 0x4e, 0x5f, 0x46, 0x41, - 0x49, 0x4c, 0x45, 0x44, 0x10, 0x0e, 0x12, 0x25, 0x0a, 0x21, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, - 0x46, 0x53, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, - 0x59, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x0f, 0x12, 0x2f, 0x0a, - 0x2b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, - 0x49, 0x56, 0x45, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, - 0x52, 0x59, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x10, 0x22, 0x42, - 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x53, 0x54, 0x41, 0x54, 0x45, - 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, - 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, - 0x10, 0x02, 0x22, 0x4d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, - 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, - 0x73, 0x22, 0x71, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, - 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x52, 0x0a, 0x0d, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x2d, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x27, 0x12, - 0x25, 0x49, 0x66, 0x20, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x73, 0x20, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x0c, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x22, 0x46, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, - 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x68, 0x65, - 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x05, - 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x65, 0x6c, - 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, - 0x73, 0x65, 0x72, 0x73, 0x42, 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, - 0x63, 0x69, 0x64, 0x65, 0x78, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, - 0x2f, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x73, 0x22, 0x8e, 0x02, 0x0a, 0x0b, 0x47, 0x55, 0x49, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x12, 0x4b, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x55, 0x49, 0x53, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x55, 0x49, 0x4d, 0x6f, 0x64, 0x65, 0x42, 0x1c, 0xe2, 0xfc, 0xe3, + 0xc4, 0x01, 0x16, 0x12, 0x14, 0x55, 0x73, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, + 0x61, 0x63, 0x65, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, + 0x58, 0x0a, 0x0b, 0x63, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x08, 0x42, 0x37, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x31, 0x12, 0x2f, 0x49, 0x66, + 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x20, 0x73, 0x68, 0x6f, 0x77, 0x20, 0x66, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x61, 0x72, 0x65, 0x20, 0x62, 0x65, + 0x69, 0x6e, 0x67, 0x20, 0x63, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x65, 0x64, 0x2e, 0x52, 0x0a, 0x63, + 0x61, 0x6e, 0x61, 0x72, 0x79, 0x4d, 0x6f, 0x64, 0x65, 0x22, 0x2c, 0x0a, 0x06, 0x55, 0x49, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x41, 0x53, 0x49, 0x43, 0x10, 0x00, 0x12, 0x0c, + 0x0a, 0x08, 0x41, 0x44, 0x56, 0x41, 0x4e, 0x43, 0x45, 0x44, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, + 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x02, 0x3a, 0x2a, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0x24, 0x0a, + 0x22, 0x55, 0x73, 0x65, 0x72, 0x20, 0x47, 0x55, 0x49, 0x20, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x2e, 0x22, 0x2e, 0x0a, 0x06, 0x55, 0x49, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, + 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x22, 0xf4, 0x01, 0x0a, 0x19, 0x41, 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, + 0x65, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x69, 0x74, + 0x73, 0x12, 0x35, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x09, 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, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x18, 0x13, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x0f, 0x61, 0x75, 0x74, 0x68, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, + 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x23, + 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x6b, 0x73, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x49, 0x4c, 0x69, 0x6e, 0x6b, 0x52, 0x05, 0x6c, 0x69, + 0x6e, 0x6b, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x69, 0x5f, + 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x75, 0x69, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xaf, 0x03, 0x0a, 0x0a, 0x41, + 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x12, 0x39, 0x0a, 0x08, 0x75, 0x73, 0x65, + 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1d, 0xe2, 0xfc, 0xe3, + 0xc4, 0x01, 0x17, 0x12, 0x15, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, + 0x55, 0x49, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x19, 0xe2, 0xfc, 0xe3, 0xc4, + 0x01, 0x13, 0x12, 0x11, 0x55, 0x73, 0x65, 0x72, 0x20, 0x55, 0x49, 0x20, 0x73, 0x65, 0x74, 0x74, + 0x69, 0x6e, 0x67, 0x73, 0x2e, 0x52, 0x08, 0x73, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, + 0x94, 0x01, 0x0a, 0x10, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, + 0x61, 0x69, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x42, 0x47, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x41, 0x12, 0x3f, 0x55, 0x73, 0x65, 0x72, 0x27, 0x73, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x20, 0x74, 0x72, 0x61, 0x69, 0x74, 0x73, 0x20, 0x28, 0x77, + 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x55, 0x49, 0x29, 0x2e, 0x52, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x54, 0x72, 0x61, 0x69, 0x74, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x41, 0x70, 0x69, 0x47, 0x72, 0x72, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x22, + 0x4b, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x55, + 0x53, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, + 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, + 0x4e, 0x44, 0x41, 0x52, 0x44, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x55, 0x53, 0x45, 0x52, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x41, 0x44, 0x4d, 0x49, 0x4e, 0x10, 0x02, 0x22, 0x2d, 0x0a, 0x15, + 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0xfa, 0x06, 0x0a, 0x10, + 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x49, 0x0a, 0x11, + 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x10, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x31, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x42, + 0x13, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x0d, 0x0a, 0x0b, 0x52, 0x44, 0x46, 0x44, 0x61, 0x74, 0x65, + 0x74, 0x69, 0x6d, 0x65, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xb8, 0x04, 0x0a, 0x04, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, + 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, + 0x54, 0x5f, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x52, 0x4f, 0x47, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x22, 0x0a, 0x1e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, + 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x20, 0x0a, 0x1c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x4e, + 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, + 0x53, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x24, 0x0a, 0x20, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, + 0x52, 0x4f, 0x4e, 0x5f, 0x4a, 0x4f, 0x42, 0x5f, 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, + 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, + 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x47, 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x05, 0x12, 0x1e, + 0x0a, 0x1a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x4e, 0x54, 0x5f, 0x41, 0x50, 0x50, 0x52, + 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x47, 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x06, 0x12, 0x22, + 0x0a, 0x1e, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x4f, 0x4e, 0x5f, 0x4a, 0x4f, 0x42, 0x5f, + 0x41, 0x50, 0x50, 0x52, 0x4f, 0x56, 0x41, 0x4c, 0x5f, 0x47, 0x52, 0x41, 0x4e, 0x54, 0x45, 0x44, + 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, 0x46, + 0x49, 0x4c, 0x45, 0x5f, 0x43, 0x4f, 0x4c, 0x4c, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x08, 0x12, + 0x23, 0x0a, 0x1f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, + 0x5f, 0x43, 0x4f, 0x4c, 0x4c, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, + 0x45, 0x44, 0x10, 0x09, 0x12, 0x15, 0x0a, 0x11, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x48, 0x55, 0x4e, + 0x54, 0x5f, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x45, 0x44, 0x10, 0x0a, 0x12, 0x1f, 0x0a, 0x1b, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, 0x45, + 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x45, 0x44, 0x10, 0x0b, 0x12, 0x27, 0x0a, 0x23, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x41, 0x52, 0x43, 0x48, 0x49, 0x56, + 0x45, 0x5f, 0x47, 0x45, 0x4e, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x46, 0x41, 0x49, + 0x4c, 0x45, 0x44, 0x10, 0x0c, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4c, + 0x4f, 0x57, 0x5f, 0x52, 0x55, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, + 0x10, 0x0d, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4c, 0x4f, 0x57, 0x5f, + 0x52, 0x55, 0x4e, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x0e, 0x12, 0x25, 0x0a, 0x21, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, + 0x44, 0x10, 0x0f, 0x12, 0x2f, 0x0a, 0x2b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x56, 0x46, 0x53, 0x5f, + 0x52, 0x45, 0x43, 0x55, 0x52, 0x53, 0x49, 0x56, 0x45, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x5f, 0x44, + 0x49, 0x52, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x59, 0x5f, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, + 0x45, 0x44, 0x10, 0x10, 0x22, 0x42, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0f, 0x0a, + 0x0b, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x45, 0x54, 0x10, 0x00, 0x12, 0x11, + 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, + 0x01, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x50, + 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x4d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x55, 0x73, 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x71, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x52, 0x0a, 0x0d, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x5f, + 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x42, 0x2d, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x27, 0x12, 0x25, 0x49, 0x66, 0x20, 0x73, 0x65, 0x74, 0x2c, 0x20, 0x63, + 0x6c, 0x65, 0x61, 0x72, 0x73, 0x20, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6e, 0x6f, + 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x0c, 0x63, 0x6c, + 0x65, 0x61, 0x72, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x46, 0x0a, 0x14, 0x53, 0x65, + 0x74, 0x47, 0x55, 0x49, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x74, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x05, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x2d, 0x0a, 0x05, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x56, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x55, + 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x22, 0x7d, 0x0a, 0x08, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x04, + 0x73, 0x70, 0x65, 0x63, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x53, 0x70, 0x65, 0x63, 0x52, + 0x04, 0x73, 0x70, 0x65, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x32, 0x0a, 0x09, 0x46, 0x61, 0x76, + 0x6f, 0x72, 0x69, 0x74, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x61, + 0x76, 0x6f, 0x72, 0x69, 0x74, 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x42, 0x31, 0x5a, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x64, 0x65, 0x78, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, + 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1165,7 +1299,7 @@ func file_users_proto_rawDescGZIP() []byte { } var file_users_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_users_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_users_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_users_proto_goTypes = []interface{}{ (GUISettings_UIMode)(0), // 0: proto.GUISettings.UIMode (ApiGrrUser_UserType)(0), // 1: proto.ApiGrrUser.UserType @@ -1182,12 +1316,15 @@ var file_users_proto_goTypes = []interface{}{ (*GetUserNotificationsRequest)(nil), // 12: proto.GetUserNotificationsRequest (*SetGUIOptionsRequest)(nil), // 13: proto.SetGUIOptionsRequest (*Users)(nil), // 14: proto.Users - (*proto.ApiClientACL)(nil), // 15: proto.ApiClientACL + (*Favorite)(nil), // 15: proto.Favorite + (*Favorites)(nil), // 16: proto.Favorites + (*proto.ApiClientACL)(nil), // 17: proto.ApiClientACL + (*proto1.ArtifactSpec)(nil), // 18: proto.ArtifactSpec } var file_users_proto_depIdxs = []int32{ - 15, // 0: proto.VelociraptorUser.Permissions:type_name -> proto.ApiClientACL + 17, // 0: proto.VelociraptorUser.Permissions:type_name -> proto.ApiClientACL 0, // 1: proto.GUISettings.mode:type_name -> proto.GUISettings.UIMode - 15, // 2: proto.ApiGrrUserInterfaceTraits.Permissions:type_name -> proto.ApiClientACL + 17, // 2: proto.ApiGrrUserInterfaceTraits.Permissions:type_name -> proto.ApiClientACL 6, // 3: proto.ApiGrrUserInterfaceTraits.links:type_name -> proto.UILink 5, // 4: proto.ApiGrrUser.settings:type_name -> proto.GUISettings 7, // 5: proto.ApiGrrUser.interface_traits:type_name -> proto.ApiGrrUserInterfaceTraits @@ -1196,11 +1333,13 @@ var file_users_proto_depIdxs = []int32{ 3, // 8: proto.UserNotification.state:type_name -> proto.UserNotification.State 10, // 9: proto.GetUserNotificationsResponse.items:type_name -> proto.UserNotification 4, // 10: proto.Users.users:type_name -> proto.VelociraptorUser - 11, // [11:11] is the sub-list for method output_type - 11, // [11:11] is the sub-list for method input_type - 11, // [11:11] is the sub-list for extension type_name - 11, // [11:11] is the sub-list for extension extendee - 0, // [0:11] is the sub-list for field type_name + 18, // 11: proto.Favorite.spec:type_name -> proto.ArtifactSpec + 15, // 12: proto.Favorites.items:type_name -> proto.Favorite + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_users_proto_init() } @@ -1341,6 +1480,30 @@ func file_users_proto_init() { return nil } } + file_users_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Favorite); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_users_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Favorites); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1348,7 +1511,7 @@ func file_users_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_users_proto_rawDesc, NumEnums: 4, - NumMessages: 11, + NumMessages: 13, NumExtensions: 0, NumServices: 0, }, diff --git a/api/proto/users.proto b/api/proto/users.proto index f5f4280ae9c..359bc4f889b 100644 --- a/api/proto/users.proto +++ b/api/proto/users.proto @@ -2,6 +2,7 @@ syntax = "proto3"; import "proto/semantic.proto"; import "acls/proto/acl.proto"; +import "flows/proto/artifact_collector.proto"; package proto; @@ -156,4 +157,17 @@ message SetGUIOptionsRequest { message Users { repeated VelociraptorUser users = 1; +} + +// Store favorite collections (essential preset collection specs) +message Favorite { + string name = 1; + string description = 2; + repeated ArtifactSpec spec = 3; + + string type = 4; +} + +message Favorites { + repeated Favorite items = 1; } \ No newline at end of file diff --git a/api/proto/vfs_api.pb.go b/api/proto/vfs_api.pb.go new file mode 100644 index 00000000000..bf0d59fe01f --- /dev/null +++ b/api/proto/vfs_api.pb.go @@ -0,0 +1,549 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0-devel +// protoc v3.12.3 +// source: vfs_api.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" + proto "www.velocidex.com/golang/velociraptor/actions/proto" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type VFSListResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Response string `protobuf:"bytes,1,opt,name=Response,proto3" json:"Response,omitempty"` + Columns []string `protobuf:"bytes,2,rep,name=Columns,proto3" json:"Columns,omitempty"` + Query *proto.VQLRequest `protobuf:"bytes,3,opt,name=Query,proto3" json:"Query,omitempty"` + Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + TotalRows uint64 `protobuf:"varint,7,opt,name=total_rows,json=totalRows,proto3" json:"total_rows,omitempty"` + Types []*proto.VQLTypeMap `protobuf:"bytes,8,rep,name=types,proto3" json:"types,omitempty"` + // The actual artifact that contains the data. + ClientId string `protobuf:"bytes,9,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + FlowId string `protobuf:"bytes,10,opt,name=flow_id,json=flowId,proto3" json:"flow_id,omitempty"` +} + +func (x *VFSListResponse) Reset() { + *x = VFSListResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VFSListResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VFSListResponse) ProtoMessage() {} + +func (x *VFSListResponse) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VFSListResponse.ProtoReflect.Descriptor instead. +func (*VFSListResponse) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{0} +} + +func (x *VFSListResponse) GetResponse() string { + if x != nil { + return x.Response + } + return "" +} + +func (x *VFSListResponse) GetColumns() []string { + if x != nil { + return x.Columns + } + return nil +} + +func (x *VFSListResponse) GetQuery() *proto.VQLRequest { + if x != nil { + return x.Query + } + return nil +} + +func (x *VFSListResponse) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *VFSListResponse) GetTotalRows() uint64 { + if x != nil { + return x.TotalRows + } + return 0 +} + +func (x *VFSListResponse) GetTypes() []*proto.VQLTypeMap { + if x != nil { + return x.Types + } + return nil +} + +func (x *VFSListResponse) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *VFSListResponse) GetFlowId() string { + if x != nil { + return x.FlowId + } + return "" +} + +type VFSStatDownloadRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + Accessor string `protobuf:"bytes,4,opt,name=accessor,proto3" json:"accessor,omitempty"` + Components []string `protobuf:"bytes,6,rep,name=components,proto3" json:"components,omitempty"` +} + +func (x *VFSStatDownloadRequest) Reset() { + *x = VFSStatDownloadRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VFSStatDownloadRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VFSStatDownloadRequest) ProtoMessage() {} + +func (x *VFSStatDownloadRequest) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VFSStatDownloadRequest.ProtoReflect.Descriptor instead. +func (*VFSStatDownloadRequest) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{1} +} + +func (x *VFSStatDownloadRequest) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *VFSStatDownloadRequest) GetAccessor() string { + if x != nil { + return x.Accessor + } + return "" +} + +func (x *VFSStatDownloadRequest) GetComponents() []string { + if x != nil { + return x.Components + } + return nil +} + +type VFSListRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + RecursionDepth uint64 `protobuf:"varint,3,opt,name=recursion_depth,json=recursionDepth,proto3" json:"recursion_depth,omitempty"` + VfsComponents []string `protobuf:"bytes,4,rep,name=vfs_components,json=vfsComponents,proto3" json:"vfs_components,omitempty"` +} + +func (x *VFSListRequest) Reset() { + *x = VFSListRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VFSListRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VFSListRequest) ProtoMessage() {} + +func (x *VFSListRequest) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VFSListRequest.ProtoReflect.Descriptor instead. +func (*VFSListRequest) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{2} +} + +func (x *VFSListRequest) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *VFSListRequest) GetRecursionDepth() uint64 { + if x != nil { + return x.RecursionDepth + } + return 0 +} + +func (x *VFSListRequest) GetVfsComponents() []string { + if x != nil { + return x.VfsComponents + } + return nil +} + +type VFSListRequestState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Components []string `protobuf:"bytes,4,rep,name=components,proto3" json:"components,omitempty"` + Accessor string `protobuf:"bytes,3,opt,name=accessor,proto3" json:"accessor,omitempty"` + Current *proto.VQLResponse `protobuf:"bytes,2,opt,name=current,proto3" json:"current,omitempty"` +} + +func (x *VFSListRequestState) Reset() { + *x = VFSListRequestState{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VFSListRequestState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VFSListRequestState) ProtoMessage() {} + +func (x *VFSListRequestState) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VFSListRequestState.ProtoReflect.Descriptor instead. +func (*VFSListRequestState) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{3} +} + +func (x *VFSListRequestState) GetComponents() []string { + if x != nil { + return x.Components + } + return nil +} + +func (x *VFSListRequestState) GetAccessor() string { + if x != nil { + return x.Accessor + } + return "" +} + +func (x *VFSListRequestState) GetCurrent() *proto.VQLResponse { + if x != nil { + return x.Current + } + return nil +} + +type VFSDownloadFileRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + VfsComponents []string `protobuf:"bytes,2,rep,name=vfs_components,json=vfsComponents,proto3" json:"vfs_components,omitempty"` +} + +func (x *VFSDownloadFileRequest) Reset() { + *x = VFSDownloadFileRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_vfs_api_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VFSDownloadFileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VFSDownloadFileRequest) ProtoMessage() {} + +func (x *VFSDownloadFileRequest) ProtoReflect() protoreflect.Message { + mi := &file_vfs_api_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VFSDownloadFileRequest.ProtoReflect.Descriptor instead. +func (*VFSDownloadFileRequest) Descriptor() ([]byte, []int) { + return file_vfs_api_proto_rawDescGZIP(), []int{4} +} + +func (x *VFSDownloadFileRequest) GetClientId() string { + if x != nil { + return x.ClientId + } + return "" +} + +func (x *VFSDownloadFileRequest) GetVfsComponents() []string { + if x != nil { + return x.VfsComponents + } + return nil +} + +var File_vfs_api_proto protoreflect.FileDescriptor + +var file_vfs_api_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x76, 0x66, 0x73, 0x5f, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x8c, 0x02, 0x0a, 0x0f, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x07, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x27, 0x0a, 0x05, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x6f, 0x77, 0x73, 0x12, + 0x27, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x61, + 0x70, 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x71, + 0x0a, 0x16, 0x56, 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, + 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, + 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x73, 0x22, 0x7d, 0x0a, 0x0e, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, + 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, + 0x70, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x75, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x70, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x66, 0x73, + 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0d, 0x76, 0x66, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, + 0x22, 0x7f, 0x0a, 0x13, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, + 0x73, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x22, 0x5c, 0x0a, 0x16, 0x56, 0x46, 0x53, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, + 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x66, 0x73, 0x5f, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0d, 0x76, 0x66, 0x73, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x42, + 0x31, 0x5a, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x64, 0x65, 0x78, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x76, 0x65, 0x6c, 0x6f, + 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_vfs_api_proto_rawDescOnce sync.Once + file_vfs_api_proto_rawDescData = file_vfs_api_proto_rawDesc +) + +func file_vfs_api_proto_rawDescGZIP() []byte { + file_vfs_api_proto_rawDescOnce.Do(func() { + file_vfs_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_vfs_api_proto_rawDescData) + }) + return file_vfs_api_proto_rawDescData +} + +var file_vfs_api_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_vfs_api_proto_goTypes = []interface{}{ + (*VFSListResponse)(nil), // 0: proto.VFSListResponse + (*VFSStatDownloadRequest)(nil), // 1: proto.VFSStatDownloadRequest + (*VFSListRequest)(nil), // 2: proto.VFSListRequest + (*VFSListRequestState)(nil), // 3: proto.VFSListRequestState + (*VFSDownloadFileRequest)(nil), // 4: proto.VFSDownloadFileRequest + (*proto.VQLRequest)(nil), // 5: proto.VQLRequest + (*proto.VQLTypeMap)(nil), // 6: proto.VQLTypeMap + (*proto.VQLResponse)(nil), // 7: proto.VQLResponse +} +var file_vfs_api_proto_depIdxs = []int32{ + 5, // 0: proto.VFSListResponse.Query:type_name -> proto.VQLRequest + 6, // 1: proto.VFSListResponse.types:type_name -> proto.VQLTypeMap + 7, // 2: proto.VFSListRequestState.current:type_name -> proto.VQLResponse + 3, // [3:3] is the sub-list for method output_type + 3, // [3:3] is the sub-list for method input_type + 3, // [3:3] is the sub-list for extension type_name + 3, // [3:3] is the sub-list for extension extendee + 0, // [0:3] is the sub-list for field type_name +} + +func init() { file_vfs_api_proto_init() } +func file_vfs_api_proto_init() { + if File_vfs_api_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_vfs_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VFSListResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vfs_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VFSStatDownloadRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vfs_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VFSListRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vfs_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VFSListRequestState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_vfs_api_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VFSDownloadFileRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_vfs_api_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_vfs_api_proto_goTypes, + DependencyIndexes: file_vfs_api_proto_depIdxs, + MessageInfos: file_vfs_api_proto_msgTypes, + }.Build() + File_vfs_api_proto = out.File + file_vfs_api_proto_rawDesc = nil + file_vfs_api_proto_goTypes = nil + file_vfs_api_proto_depIdxs = nil +} diff --git a/api/proto/vfs_api.proto b/api/proto/vfs_api.proto new file mode 100644 index 00000000000..135986d033f --- /dev/null +++ b/api/proto/vfs_api.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +import "actions/proto/vql.proto"; + +package proto; + +option go_package = "www.velocidex.com/golang/velociraptor/api/proto"; + +// Messages to interact with the API + +message VFSListResponse { + string Response = 1; + repeated string Columns = 2; + VQLRequest Query = 3; + uint64 timestamp = 4; + uint64 total_rows = 7; + repeated VQLTypeMap types = 8; + + // The actual artifact that contains the data. + string client_id = 9; + string flow_id = 10; +} + +message VFSStatDownloadRequest { + string client_id = 1; + string accessor = 4; + + repeated string components = 6; +} + +message VFSListRequest { + string client_id = 1; + uint64 recursion_depth = 3; + repeated string vfs_components = 4; +} + +message VFSListRequestState { + repeated string components = 4; + string accessor = 3; + VQLResponse current = 2; +} + +message VFSDownloadFileRequest { + string client_id = 1; + + repeated string vfs_components = 2; +} diff --git a/api/proxy.go b/api/proxy.go index d79915efa1c..7693858fbb6 100644 --- a/api/proxy.go +++ b/api/proxy.go @@ -38,7 +38,7 @@ import ( "www.velocidex.com/golang/velociraptor/constants" crypto_utils "www.velocidex.com/golang/velociraptor/crypto/utils" file_store "www.velocidex.com/golang/velociraptor/file_store" - "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/accessors" "www.velocidex.com/golang/velociraptor/grpc_client" "www.velocidex.com/golang/velociraptor/logging" ) @@ -141,10 +141,6 @@ func PrepareGUIMux( auther.AuthenticateUserHandler( config_obj, vfsFileDownloadHandler(config_obj)))) - mux.Handle(base+"/api/v1/DownloadVFSFolder", csrfProtect(config_obj, - auther.AuthenticateUserHandler( - config_obj, vfsFolderDownloadHandler(config_obj)))) - mux.Handle(base+"/api/v1/UploadTool", csrfProtect(config_obj, auther.AuthenticateUserHandler( config_obj, toolUploadHandler(config_obj)))) @@ -153,7 +149,7 @@ func PrepareGUIMux( mux.Handle(base+"/downloads/", csrfProtect(config_obj, auther.AuthenticateUserHandler( config_obj, http.StripPrefix(base, forceMime(http.FileServer( - api.NewFileSystem( + accessors.NewFileSystem( config_obj, file_store.GetFileStore(config_obj), "/downloads/"))))))) @@ -162,7 +158,7 @@ func PrepareGUIMux( mux.Handle(base+"/notebooks/", csrfProtect(config_obj, auther.AuthenticateUserHandler( config_obj, http.StripPrefix(base, forceMime(http.FileServer( - api.NewFileSystem( + accessors.NewFileSystem( config_obj, file_store.GetFileStore(config_obj), "/notebooks/"))))))) diff --git a/api/server_monitoring.go b/api/server_monitoring.go index e4e6e0f083e..cdc3e3dd51e 100644 --- a/api/server_monitoring.go +++ b/api/server_monitoring.go @@ -2,9 +2,9 @@ package api import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" - "www.velocidex.com/golang/velociraptor/constants" "www.velocidex.com/golang/velociraptor/datastore" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" + "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/services" ) @@ -17,7 +17,7 @@ func getServerMonitoringState(config_obj *config_proto.Config) ( result := &flows_proto.ArtifactCollectorArgs{} err = db.GetSubject(config_obj, - constants.ServerMonitoringFlowURN, + paths.ServerMonitoringFlowURN, result, ) _ = err // if an error we return an empty collector args. @@ -38,6 +38,6 @@ func setServerMonitoringState( } return db.SetSubject( - config_obj, constants.ServerMonitoringFlowURN, + config_obj, paths.ServerMonitoringFlowURN, args) } diff --git a/api/users.go b/api/users.go index cca8014e4f6..9999191fd8c 100644 --- a/api/users.go +++ b/api/users.go @@ -38,3 +38,12 @@ func (self *ApiServer) GetUsers( return result, nil } + +func (self *ApiServer) GetUserFavorites( + ctx context.Context, + in *api_proto.Favorite) (*api_proto.Favorites, error) { + + // No special permission requires to view a user's own favorites. + user_name := GetGRPCUserInfo(self.config, ctx).Name + return users.GetFavorites(self.config, user_name, in.Type) +} diff --git a/api/vfs.go b/api/vfs.go index 29d49081fd7..5bd419a4bcf 100644 --- a/api/vfs.go +++ b/api/vfs.go @@ -67,9 +67,9 @@ import ( context "golang.org/x/net/context" actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" + api_proto "www.velocidex.com/golang/velociraptor/api/proto" config_proto "www.velocidex.com/golang/velociraptor/config/proto" datastore "www.velocidex.com/golang/velociraptor/datastore" - file_store "www.velocidex.com/golang/velociraptor/file_store" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/json" "www.velocidex.com/golang/velociraptor/paths" @@ -91,14 +91,13 @@ type FileInfoRow struct { // Render the root level pseudo directory. This provides anchor points // for the other drivers in the navigation. -func renderRootVFS(client_id string) *flows_proto.VFSListResponse { - return &flows_proto.VFSListResponse{ +func renderRootVFS(client_id string) *api_proto.VFSListResponse { + return &api_proto.VFSListResponse{ Response: ` [ {"Mode": "drwxrwxrwx", "Name": "file"}, {"Mode": "drwxrwxrwx", "Name": "ntfs"}, - {"Mode": "drwxrwxrwx", "Name": "registry"}, - {"Mode": "drwxrwxrwx", "Name": "artifacts"} + {"Mode": "drwxrwxrwx", "Name": "registry"} ]`, } } @@ -107,32 +106,27 @@ func renderRootVFS(client_id string) *flows_proto.VFSListResponse { func renderDBVFS( config_obj *config_proto.Config, client_id string, - components []string) (*flows_proto.VFSListResponse, error) { + components []string) (*api_proto.VFSListResponse, error) { db, err := datastore.GetDB(config_obj) if err != nil { return nil, err } + path_manager := paths.NewClientPathManager(client_id) + // Figure out where the download info files are. - download_info_path := append([]string{ - "clients", client_id, "vfs_files"}, components...) + download_info_path := path_manager.VFSDownloadInfoPath(components) + downloaded_files, _ := db.ListChildren( + config_obj, download_info_path, 0, 1000) - downloaded_files, err := db.ListChildren( - config_obj, utils.JoinComponents(download_info_path, "/"), - 0, 1000) - if err != nil { - return nil, err - } - result := &flows_proto.VFSListResponse{} + result := &api_proto.VFSListResponse{} // Figure out where the directory info is. - vfs_path := append([]string{ - "clients", client_id, "vfs"}, components...) + vfs_path := path_manager.VFSPath(components) // If file does not exist, we have an empty response - _ = db.GetSubject( - config_obj, utils.JoinComponents(vfs_path, "/"), result) + _ = db.GetSubject(config_obj, vfs_path, result) // Empty responses mean the directory is empty - no need to // worry about downloads. @@ -145,10 +139,9 @@ func renderDBVFS( // that if there are no downloaded files, we just pass the // VFSListResponse lazily to the caller. if len(downloaded_files) > 0 { - lookup := make(map[string]string) + lookup := make(map[string]bool) for _, filename := range downloaded_files { - normalized_name := utils.Base(filename) - lookup[normalized_name] = filename + lookup[filename.Base()] = true } var rows []map[string]interface{} @@ -165,14 +158,25 @@ func renderDBVFS( continue } - filename, pres := lookup[name] + _, pres := lookup[name] if !pres { continue } + // Make a copy for each path + file_components := download_info_path.AddChild(name) download_info := &flows_proto.VFSDownloadInfo{} - err := db.GetSubject(config_obj, filename, download_info) + err := db.GetSubject( + config_obj, file_components, download_info) if err == nil { + // Support reading older + // VFSDownloadInfo protobufs which + // only contained the vfs_path and not + // the components. + if download_info.VfsPath != "" { + download_info.Components = utils.SplitComponents(download_info.VfsPath) + } + row["Download"] = download_info } } @@ -195,92 +199,15 @@ func renderDBVFS( return result, nil } -// Render VFS nodes from the filestore. -func renderFileStore( - config_obj *config_proto.Config, - components []string) (*flows_proto.VFSListResponse, error) { - var rows []*FileInfoRow - - vfs_path := utils.JoinComponents(components, "/") - items, err := file_store.GetFileStore(config_obj). - ListDirectory(vfs_path) - if err == nil { - for _, item := range items { - row := &FileInfoRow{ - Name: item.Name(), - Size: item.Size(), - Timestamp: item.ModTime().Format("2006-01-02 15:04:05"), - FullPath: utils.PathJoin(vfs_path, item.Name(), "/"), - } - - if item.IsDir() { - row.Mode = "dr-xr-xr-x" - } else { - row.Mode = "-r--r--r--" - row.Download = &flows_proto.VFSDownloadInfo{ - VfsPath: row.FullPath, - Size: uint64(item.Size()), - Mtime: uint64(item.ModTime().UnixNano() / 1000), - } - } - - rows = append(rows, row) - } - } - - encoded_rows, err := json.MarshalIndent(rows) - if err != nil { - return nil, err - } - - result := &flows_proto.VFSListResponse{ - Columns: []string{ - "Download", "Name", "Size", "Mode", "Timestamp", - }, - Response: string(encoded_rows), - Types: []*actions_proto.VQLTypeMap{ - &actions_proto.VQLTypeMap{ - Column: "Download", - Type: "Download", - }, - }, - } - - return result, nil -} - -// We export some paths from the file_store into the VFS. This -// function maps from the browser's vfs view into the file_store -// prefix. If this function returns ok, then the full filestore path -// can be obtained by joining the prefix with the vfs_path provided. -func getVFSPathPrefix(components []string, client_id string) (prefix []string, ok bool) { - if len(components) > 0 && components[0] == "artifacts" { - return []string{"clients", client_id}, true - } - - if client_id != "" && len(components) > 2 && - components[0] == "clients" && components[1] == client_id { - return nil, true - } - - return nil, false -} - func vfsListDirectory( config_obj *config_proto.Config, client_id string, - vfs_path string) (*flows_proto.VFSListResponse, error) { + components []string) (*api_proto.VFSListResponse, error) { - components := utils.SplitComponents(vfs_path) if len(components) == 0 { return renderRootVFS(client_id), nil } - prefix, ok := getVFSPathPrefix(components, client_id) - if ok { - return renderFileStore(config_obj, append(prefix, components...)) - } - return renderDBVFS(config_obj, client_id, components) } @@ -290,22 +217,22 @@ func vfsListDirectory( func vfsStatDirectory( config_obj *config_proto.Config, client_id string, - vfs_path string) (*flows_proto.VFSListResponse, error) { + vfs_components []string) (*api_proto.VFSListResponse, error) { db, err := datastore.GetDB(config_obj) if err != nil { return nil, err } - vfs_urn := fmt.Sprintf("/clients/%v/vfs/%v", client_id, vfs_path) - - result := &flows_proto.VFSListResponse{} + path_manager := paths.NewClientPathManager(client_id) + result := &api_proto.VFSListResponse{} // Regardless of error we return success - if the file does // not exist yet then it will have no flow id associated with // it. This allows the gui to watch for the VFS directory to // appear for the first time. - _ = db.GetSubject(config_obj, vfs_urn, result) + _ = db.GetSubject(config_obj, + path_manager.VFSPath(vfs_components), result) // Remove the actual response which might be large. result.Response = "" @@ -316,10 +243,11 @@ func vfsStatDirectory( func vfsStatDownload( config_obj *config_proto.Config, client_id string, - accessor, path string) (*flows_proto.VFSDownloadInfo, error) { + accessor string, + path_components []string) (*flows_proto.VFSDownloadInfo, error) { - path_manager := paths.NewFlowPathManager(client_id, "").GetVFSDownloadInfoPath( - accessor, path) + path_spec := paths.NewClientPathManager(client_id). + VFSDownloadInfoPath(path_components) db, err := datastore.GetDB(config_obj) if err != nil { @@ -332,7 +260,7 @@ func vfsStatDownload( // not exist yet then it will have no flow id associated with // it. This allows the gui to watch for the VFS directory to // appear for the first time. - err = db.GetSubject(config_obj, path_manager.Path(), result) + err = db.GetSubject(config_obj, path_spec, result) if err != nil { return nil, err } @@ -348,9 +276,7 @@ func vfsStatDownload( // GUI organizes files. In the GUI, files are organized in a tree, // where the top level directory is the accessor, the rest of the path // is passed to the accessor directly. -func GetClientPath(vfs_path string) (client_path string, accessor string) { - components := utils.SplitComponents(vfs_path) - +func GetClientPath(components []string) (client_path string, accessor string) { if len(components) == 0 { return "", "file" } @@ -366,7 +292,7 @@ func GetClientPath(vfs_path string) (client_path string, accessor string) { default: // This should not happen - try to get it using file accessor. - return vfs_path, "file" + return utils.JoinComponents(components[1:], "/"), components[0] } } @@ -374,10 +300,10 @@ func vfsRefreshDirectory( self *ApiServer, ctx context.Context, client_id string, - vfs_path string, + vfs_components []string, depth uint64) (*flows_proto.ArtifactCollectorResponse, error) { - client_path, accessor := GetClientPath(vfs_path) + client_path, accessor := GetClientPath(vfs_components) request := MakeCollectorRequest( client_id, "System.VFS.ListDirectory", "Path", client_path, diff --git a/artifacts/definitions/Demo/Plugins/GUI.yaml b/artifacts/definitions/Demo/Plugins/GUI.yaml index 51185a00fb2..3a5cad1e7d7 100644 --- a/artifacts/definitions/Demo/Plugins/GUI.yaml +++ b/artifacts/definitions/Demo/Plugins/GUI.yaml @@ -142,12 +142,21 @@ sources: -- Add the time series into the timeline. SELECT timeline_add( - key="Timestamp", name="Time 'line' &\" ", - query=T1, timeline="Test \"Timeline\"") + key="Timestamp", name="Time 你好世界 'line' &\" ", + query=T1, timeline="Test \"Timeline 你好世界\""), + timeline_add( + key="Timestamp", name="2", + query=T1, timeline="Test \"Timeline 你好世界\"") FROM scope() - type: Markdown + env: + - key: Timeline + value: Test "Timeline 你好世界" template: | - ## This super timeline should have one timeline. + ## This super timeline should have two timelines. - {{ Timeline "Test \"Timeline\"" }} + Add a timeline manually and hit refresh on this cell to + check it is being updated. + + {{ Scope "Timeline" | Timeline }} diff --git a/artifacts/definitions/Server/Internal/Inventory.yaml b/artifacts/definitions/Server/Internal/Inventory.yaml new file mode 100644 index 00000000000..1120516450e --- /dev/null +++ b/artifacts/definitions/Server/Internal/Inventory.yaml @@ -0,0 +1,5 @@ +name: Server.Internal.Inventory +description: | + An internal artifact to listen to inventory (tools) changes. + +type: INTERNAL diff --git a/artifacts/definitions/Server/Utils/SaveFavoriteFlow.yaml b/artifacts/definitions/Server/Utils/SaveFavoriteFlow.yaml new file mode 100644 index 00000000000..d20edea9d41 --- /dev/null +++ b/artifacts/definitions/Server/Utils/SaveFavoriteFlow.yaml @@ -0,0 +1,35 @@ +name: Server.Utils.SaveFavoriteFlow +description: | + Users may collect various artifacts from hosts. Sometimes it might + take a bit of effort to setup and configure just the perfect + combination of parameters and artifacts to collect. + + This artifact allows the user to save the collection into a + Favorites section, which may be used in future. + +parameters: + - name: Specs + type: json_array + description: The collection request that will be recreated. + - name: Name + description: A name for this collection template + - name: Description + description: A description for the template. + - name: Type + description: The type of favorites to save. + type: choices + default: CLIENT + choices: + - CLIENT + - SERVER + - CLIENT_EVENT + - SERVER_EVENT + +sources: + - query: | + SELECT favorites_save( + name=Name, + description=Description, + specs=Specs, + type=Type) + FROM scope() diff --git a/artifacts/proto/artifact.pb.go b/artifacts/proto/artifact.pb.go index 1a75b7fff47..9380d4d0086 100644 --- a/artifacts/proto/artifact.pb.go +++ b/artifacts/proto/artifact.pb.go @@ -21,6 +21,61 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type ArtifactEnv struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ArtifactEnv) Reset() { + *x = ArtifactEnv{} + if protoimpl.UnsafeEnabled { + mi := &file_artifact_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ArtifactEnv) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ArtifactEnv) ProtoMessage() {} + +func (x *ArtifactEnv) ProtoReflect() protoreflect.Message { + mi := &file_artifact_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ArtifactEnv.ProtoReflect.Descriptor instead. +func (*ArtifactEnv) Descriptor() ([]byte, []int) { + return file_artifact_proto_rawDescGZIP(), []int{0} +} + +func (x *ArtifactEnv) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ArtifactEnv) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + type ColumnType struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -34,7 +89,7 @@ type ColumnType struct { func (x *ColumnType) Reset() { *x = ColumnType{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[0] + mi := &file_artifact_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -47,7 +102,7 @@ func (x *ColumnType) String() string { func (*ColumnType) ProtoMessage() {} func (x *ColumnType) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[0] + mi := &file_artifact_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -60,7 +115,7 @@ func (x *ColumnType) ProtoReflect() protoreflect.Message { // Deprecated: Use ColumnType.ProtoReflect.Descriptor instead. func (*ColumnType) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{0} + return file_artifact_proto_rawDescGZIP(), []int{1} } func (x *ColumnType) GetName() string { @@ -101,7 +156,7 @@ type ArtifactParameter struct { func (x *ArtifactParameter) Reset() { *x = ArtifactParameter{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[1] + mi := &file_artifact_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -114,7 +169,7 @@ func (x *ArtifactParameter) String() string { func (*ArtifactParameter) ProtoMessage() {} func (x *ArtifactParameter) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[1] + mi := &file_artifact_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -127,7 +182,7 @@ func (x *ArtifactParameter) ProtoReflect() protoreflect.Message { // Deprecated: Use ArtifactParameter.ProtoReflect.Descriptor instead. func (*ArtifactParameter) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{1} + return file_artifact_proto_rawDescGZIP(), []int{2} } func (x *ArtifactParameter) GetName() string { @@ -177,14 +232,15 @@ type NotebookSourceCell struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Template string `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Template string `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Env []*ArtifactEnv `protobuf:"bytes,3,rep,name=env,proto3" json:"env,omitempty"` } func (x *NotebookSourceCell) Reset() { *x = NotebookSourceCell{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[2] + mi := &file_artifact_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -197,7 +253,7 @@ func (x *NotebookSourceCell) String() string { func (*NotebookSourceCell) ProtoMessage() {} func (x *NotebookSourceCell) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[2] + mi := &file_artifact_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -210,7 +266,7 @@ func (x *NotebookSourceCell) ProtoReflect() protoreflect.Message { // Deprecated: Use NotebookSourceCell.ProtoReflect.Descriptor instead. func (*NotebookSourceCell) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{2} + return file_artifact_proto_rawDescGZIP(), []int{3} } func (x *NotebookSourceCell) GetTemplate() string { @@ -227,6 +283,13 @@ func (x *NotebookSourceCell) GetType() string { return "" } +func (x *NotebookSourceCell) GetEnv() []*ArtifactEnv { + if x != nil { + return x.Env + } + return nil +} + type ArtifactSource struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -245,7 +308,7 @@ type ArtifactSource struct { func (x *ArtifactSource) Reset() { *x = ArtifactSource{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[3] + mi := &file_artifact_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -258,7 +321,7 @@ func (x *ArtifactSource) String() string { func (*ArtifactSource) ProtoMessage() {} func (x *ArtifactSource) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[3] + mi := &file_artifact_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -271,7 +334,7 @@ func (x *ArtifactSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ArtifactSource.ProtoReflect.Descriptor instead. func (*ArtifactSource) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{3} + return file_artifact_proto_rawDescGZIP(), []int{4} } func (x *ArtifactSource) GetName() string { @@ -334,7 +397,7 @@ type Report struct { func (x *Report) Reset() { *x = Report{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[4] + mi := &file_artifact_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -347,7 +410,7 @@ func (x *Report) String() string { func (*Report) ProtoMessage() {} func (x *Report) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[4] + mi := &file_artifact_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -360,7 +423,7 @@ func (x *Report) ProtoReflect() protoreflect.Message { // Deprecated: Use Report.ProtoReflect.Descriptor instead. func (*Report) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{4} + return file_artifact_proto_rawDescGZIP(), []int{5} } func (x *Report) GetType() string { @@ -438,7 +501,7 @@ type Artifact struct { func (x *Artifact) Reset() { *x = Artifact{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[5] + mi := &file_artifact_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -451,7 +514,7 @@ func (x *Artifact) String() string { func (*Artifact) ProtoMessage() {} func (x *Artifact) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[5] + mi := &file_artifact_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -464,7 +527,7 @@ func (x *Artifact) ProtoReflect() protoreflect.Message { // Deprecated: Use Artifact.ProtoReflect.Descriptor instead. func (*Artifact) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{5} + return file_artifact_proto_rawDescGZIP(), []int{6} } func (x *Artifact) GetName() string { @@ -597,7 +660,7 @@ type ArtifactDescriptors struct { func (x *ArtifactDescriptors) Reset() { *x = ArtifactDescriptors{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[6] + mi := &file_artifact_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -610,7 +673,7 @@ func (x *ArtifactDescriptors) String() string { func (*ArtifactDescriptors) ProtoMessage() {} func (x *ArtifactDescriptors) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[6] + mi := &file_artifact_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -623,7 +686,7 @@ func (x *ArtifactDescriptors) ProtoReflect() protoreflect.Message { // Deprecated: Use ArtifactDescriptors.ProtoReflect.Descriptor instead. func (*ArtifactDescriptors) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{6} + return file_artifact_proto_rawDescGZIP(), []int{7} } func (x *ArtifactDescriptors) GetItems() []*Artifact { @@ -680,7 +743,7 @@ type Tool struct { func (x *Tool) Reset() { *x = Tool{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[7] + mi := &file_artifact_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -693,7 +756,7 @@ func (x *Tool) String() string { func (*Tool) ProtoMessage() {} func (x *Tool) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[7] + mi := &file_artifact_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -706,7 +769,7 @@ func (x *Tool) ProtoReflect() protoreflect.Message { // Deprecated: Use Tool.ProtoReflect.Descriptor instead. func (*Tool) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{7} + return file_artifact_proto_rawDescGZIP(), []int{8} } func (x *Tool) GetName() string { @@ -806,7 +869,7 @@ type ThirdParty struct { func (x *ThirdParty) Reset() { *x = ThirdParty{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[8] + mi := &file_artifact_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -819,7 +882,7 @@ func (x *ThirdParty) String() string { func (*ThirdParty) ProtoMessage() {} func (x *ThirdParty) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[8] + mi := &file_artifact_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -832,7 +895,7 @@ func (x *ThirdParty) ProtoReflect() protoreflect.Message { // Deprecated: Use ThirdParty.ProtoReflect.Descriptor instead. func (*ThirdParty) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{8} + return file_artifact_proto_rawDescGZIP(), []int{9} } func (x *ThirdParty) GetTools() []*Tool { @@ -865,7 +928,7 @@ type Resources struct { func (x *Resources) Reset() { *x = Resources{} if protoimpl.UnsafeEnabled { - mi := &file_artifact_proto_msgTypes[9] + mi := &file_artifact_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -878,7 +941,7 @@ func (x *Resources) String() string { func (*Resources) ProtoMessage() {} func (x *Resources) ProtoReflect() protoreflect.Message { - mi := &file_artifact_proto_msgTypes[9] + mi := &file_artifact_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -891,7 +954,7 @@ func (x *Resources) ProtoReflect() protoreflect.Message { // Deprecated: Use Resources.ProtoReflect.Descriptor instead. func (*Resources) Descriptor() ([]byte, []int) { - return file_artifact_proto_rawDescGZIP(), []int{9} + return file_artifact_proto_rawDescGZIP(), []int{10} } func (x *Resources) GetTimeout() uint64 { @@ -927,256 +990,262 @@ var File_artifact_proto protoreflect.FileDescriptor var file_artifact_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 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, 0x56, 0x0a, - 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x99, 0x03, 0x0a, 0x11, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, - 0x63, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x07, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x69, - 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0c, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x3a, 0xe0, - 0x01, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0xd9, 0x01, 0x0a, 0xd6, 0x01, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x20, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, - 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x20, 0x74, 0x6f, - 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x4e, 0x4f, 0x54, 0x45, - 0x3a, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x2d, 0x20, 0x69, - 0x66, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6e, 0x65, 0x65, 0x64, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, - 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, - 0x65, 0x72, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x20, 0x65, - 0x2e, 0x67, 0x2e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x75, 0x73, - 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4a, 0x53, 0x4f, 0x4e, 0x50, 0x61, 0x72, 0x73, - 0x65, 0x28, 0x29, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x2e, 0x22, 0x44, 0x0a, 0x12, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xca, 0x05, 0x0a, 0x0e, 0x41, 0x72, 0x74, 0x69, - 0x66, 0x61, 0x63, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0xaf, 0x01, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x9a, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, - 0x01, 0x93, 0x01, 0x12, 0x90, 0x01, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, - 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, - 0x65, 0x74, 0x20, 0x77, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, - 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, - 0x63, 0x74, 0x20, 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, - 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x61, - 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2e, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x8d, 0x01, 0x0a, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x6b, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x65, 0x12, 0x63, 0x41, 0x20, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x20, 0x4e, 0x6f, 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, - 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, - 0x74, 0x68, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x68, 0x0a, 0x0c, - 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x44, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x3e, 0x12, 0x3c, 0x41, 0x20, 0x56, 0x51, - 0x4c, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, - 0x62, 0x65, 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x69, - 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, - 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, - 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x18, 0x12, 0x16, 0x41, - 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x74, 0x0a, 0x07, - 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x5a, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x54, 0x12, 0x52, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, - 0x68, 0x61, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2e, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, - 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, - 0x65, 0x73, 0x12, 0x35, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, - 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x52, - 0x08, 0x6e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x29, 0xda, 0xfc, 0xe3, 0xc4, 0x01, - 0x23, 0x0a, 0x21, 0x57, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x64, - 0x61, 0x74, 0x61, 0x2e, 0x22, 0xd8, 0x02, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, - 0x3a, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xe2, - 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x54, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x3a, 0x20, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x2c, 0x20, 0x53, - 0x45, 0x52, 0x56, 0x45, 0x52, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, - 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, - 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x3a, - 0x8d, 0x01, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0x86, 0x01, 0x0a, 0x83, 0x01, 0x41, 0x20, 0x72, 0x65, - 0x70, 0x6f, 0x72, 0x74, 0x20, 0x69, 0x73, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, - 0x64, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, - 0x74, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x68, 0x65, - 0x72, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, - 0x6c, 0x65, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, - 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x22, - 0xc2, 0x0c, 0x0a, 0x08, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0xb1, 0x01, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x9c, 0x01, 0xe2, 0xfc, - 0xe3, 0xc4, 0x01, 0x95, 0x01, 0x12, 0x92, 0x01, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, + 0x65, 0x6d, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x35, 0x0a, + 0x0b, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0x56, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x99, 0x03, 0x0a, + 0x11, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, + 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x63, 0x68, 0x6f, 0x69, 0x63, 0x65, 0x73, + 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, + 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x3a, 0xe0, 0x01, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0xd9, 0x01, 0x0a, + 0xd6, 0x01, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x20, 0x6d, 0x61, 0x79, 0x20, + 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x20, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x65, + 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, 0x70, + 0x72, 0x69, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x2e, 0x20, 0x4e, 0x4f, 0x54, 0x45, 0x3a, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x73, 0x20, 0x2d, 0x20, 0x69, 0x66, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x73, 0x65, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x75, + 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x20, 0x65, 0x2e, 0x67, 0x2e, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, + 0x4a, 0x53, 0x4f, 0x4e, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4a, + 0x53, 0x4f, 0x4e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x28, 0x29, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x22, 0x6a, 0x0a, 0x12, 0x4e, 0x6f, 0x74, 0x65, + 0x62, 0x6f, 0x6f, 0x6b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x12, 0x1a, + 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x24, + 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x45, 0x6e, 0x76, 0x52, + 0x03, 0x65, 0x6e, 0x76, 0x22, 0xca, 0x05, 0x0a, 0x0e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0xaf, 0x01, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x9a, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x93, 0x01, + 0x12, 0x90, 0x01, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73, 0x65, 0x74, 0x20, + 0x77, 0x65, 0x20, 0x75, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, + 0x69, 0x74, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72, 0x20, 0x77, 0x69, + 0x6c, 0x6c, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x2e, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x8d, 0x01, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x6b, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x65, 0x12, 0x63, 0x41, 0x20, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x6f, + 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x20, 0x4e, + 0x6f, 0x74, 0x65, 0x20, 0x69, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x6f, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, + 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x68, 0x0a, 0x0c, 0x70, 0x72, 0x65, + 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x44, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x3e, 0x12, 0x3c, 0x41, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x65, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, + 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x20, + 0x74, 0x6f, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x1e, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x18, 0x12, 0x16, 0x41, 0x20, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x71, 0x75, 0x65, + 0x72, 0x79, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x74, 0x0a, 0x07, 0x71, 0x75, 0x65, + 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x5a, 0xe2, 0xfc, 0xe3, 0xc4, + 0x01, 0x54, 0x12, 0x52, 0x51, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, + 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x6f, 0x72, 0x64, + 0x65, 0x72, 0x2e, 0x20, 0x4f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x71, 0x75, + 0x65, 0x72, 0x79, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, + 0x35, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4e, 0x6f, 0x74, 0x65, 0x62, 0x6f, + 0x6f, 0x6b, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x65, 0x6c, 0x6c, 0x52, 0x08, 0x6e, 0x6f, + 0x74, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x3a, 0x29, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0x23, 0x0a, 0x21, + 0x57, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x64, 0x61, 0x74, 0x61, + 0x2e, 0x22, 0xd8, 0x02, 0x0a, 0x06, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3a, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, + 0x01, 0x20, 0x12, 0x1e, 0x54, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x70, 0x6f, + 0x72, 0x74, 0x3a, 0x20, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x2c, 0x20, 0x53, 0x45, 0x52, 0x56, + 0x45, 0x52, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, + 0x6f, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, + 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x12, 0x38, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x3a, 0x8d, 0x01, 0xda, + 0xfc, 0xe3, 0xc4, 0x01, 0x86, 0x01, 0x0a, 0x83, 0x01, 0x41, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, + 0x74, 0x20, 0x69, 0x73, 0x20, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x66, + 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x63, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, + 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, + 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73, 0x20, 0x67, 0x65, 0x6e, + 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x20, 0x6f, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x2e, 0x22, 0xc2, 0x0c, 0x0a, + 0x08, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0xb1, 0x01, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x9c, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, + 0x95, 0x01, 0x12, 0x92, 0x01, 0x54, 0x68, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x20, 0x53, + 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, + 0x64, 0x6f, 0x74, 0x73, 0x2e, 0x20, 0x41, 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, 0x6c, 0x20, 0x73, + 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x72, 0x65, 0x61, + 0x6b, 0x20, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, + 0x68, 0x20, 0x64, 0x6f, 0x74, 0x20, 0x65, 0x2e, 0x67, 0x2e, 0x20, 0x4c, 0x69, 0x6e, 0x75, 0x78, + 0x2e, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x43, 0x68, 0x72, 0x6f, 0x6d, 0x65, + 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x51, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x2f, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x29, 0x12, 0x27, 0x57, 0x68, 0x61, 0x74, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x69, 0x73, + 0x20, 0x74, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x2e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x37, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x1f, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x19, 0x12, 0x17, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x2e, 0x20, 0x53, 0x68, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x75, 0x6e, 0x69, 0x71, - 0x75, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, - 0x69, 0x6e, 0x20, 0x64, 0x6f, 0x74, 0x73, 0x2e, 0x20, 0x41, 0x20, 0x75, 0x73, 0x65, 0x66, 0x75, - 0x6c, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, - 0x72, 0x65, 0x61, 0x6b, 0x20, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x20, - 0x77, 0x69, 0x74, 0x68, 0x20, 0x64, 0x6f, 0x74, 0x20, 0x65, 0x2e, 0x67, 0x2e, 0x20, 0x4c, 0x69, - 0x6e, 0x75, 0x78, 0x2e, 0x42, 0x72, 0x6f, 0x77, 0x73, 0x65, 0x72, 0x73, 0x2e, 0x43, 0x68, 0x72, - 0x6f, 0x6d, 0x65, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x51, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x29, 0x12, 0x27, 0x57, - 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x20, 0x69, 0x73, 0x20, 0x74, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x37, 0x0a, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x1f, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x19, 0x12, 0x17, 0x41, 0x75, 0x74, - 0x68, 0x6f, 0x72, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x2e, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x09, - 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x42, - 0x26, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x41, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, - 0x63, 0x65, 0x12, 0x73, 0x0a, 0x14, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, - 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, - 0x42, 0x40, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x3a, 0x12, 0x38, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, - 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x70, 0x65, 0x72, - 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x2e, 0x52, 0x13, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x50, 0x65, 0x72, 0x6d, - 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, - 0x18, 0x0f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, - 0x6f, 0x6f, 0x6c, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x68, 0x0a, 0x0c, 0x70, 0x72, - 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x44, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x3e, 0x12, 0x3c, 0x41, 0x20, 0x56, 0x51, 0x4c, 0x20, - 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, - 0x20, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x6c, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x42, 0x32, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2c, 0x12, 0x2a, 0x50, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x73, 0x12, 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x3b, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x35, 0x12, 0x33, 0x54, 0x68, 0x65, 0x20, 0x74, 0x79, - 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x20, 0x43, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x2c, 0x20, - 0x45, 0x56, 0x45, 0x4e, 0x54, 0x2c, 0x20, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x52, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x12, 0x5a, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x29, 0xe2, 0xfc, 0xe3, - 0xc4, 0x01, 0x23, 0x12, 0x21, 0x57, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x69, 0x74, 0x73, - 0x20, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, - 0x6a, 0x0a, 0x07, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x09, - 0x42, 0x50, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x4a, 0x12, 0x48, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, - 0x20, 0x6f, 0x66, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, - 0x63, 0x74, 0x73, 0x27, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x56, 0x51, 0x4c, 0x20, - 0x74, 0x6f, 0x20, 0x70, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, - 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x2e, 0x52, 0x07, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x06, 0x65, - 0x78, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x42, 0x63, 0xe2, 0xfc, 0xe3, - 0xc4, 0x01, 0x5d, 0x12, 0x5b, 0x56, 0x51, 0x4c, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, - 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x2e, 0x20, 0x49, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, - 0x61, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x69, 0x6d, - 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, - 0x52, 0x06, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x6d, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x44, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x3e, - 0x12, 0x3c, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x70, 0x6f, - 0x72, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, - 0x6c, 0x79, 0x20, 0x70, 0x6f, 0x73, 0x74, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, - 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x07, - 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x75, 0x6d, - 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x38, 0x0a, - 0x03, 0x72, 0x61, 0x77, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, - 0x01, 0x20, 0x12, 0x1e, 0x54, 0x68, 0x65, 0x20, 0x72, 0x61, 0x77, 0x20, 0x59, 0x41, 0x4d, 0x4c, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x2e, 0x52, 0x03, 0x72, 0x61, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x69, - 0x6c, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x69, - 0x6c, 0x65, 0x64, 0x3a, 0x7f, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0x79, 0x0a, 0x77, 0x41, 0x6e, 0x20, - 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x77, 0x72, 0x61, 0x70, 0x73, 0x20, 0x61, - 0x20, 0x56, 0x51, 0x4c, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, - 0x75, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x2c, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, - 0x65, 0x64, 0x20, 0x77, 0x61, 0x79, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, - 0x20, 0x61, 0x72, 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x63, - 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, - 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x69, 0x6e, 0x67, 0x20, 0x74, - 0x68, 0x65, 0x6d, 0x2e, 0x22, 0x3c, 0x0a, 0x13, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x05, 0x69, 0x74, 0x65, - 0x6d, 0x73, 0x22, 0x82, 0x03, 0x0a, 0x04, 0x54, 0x6f, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, - 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x5f, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x73, 0x73, 0x65, - 0x74, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, - 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, - 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x55, 0x72, 0x6c, 0x12, - 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, - 0x0a, 0x0e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x74, 0x6f, 0x72, - 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, - 0x6c, 0x69, 0x7a, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6d, 0x61, 0x74, 0x65, - 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x22, 0x4a, 0x0a, 0x0b, 0x74, 0x68, 0x69, 0x72, 0x64, - 0x5f, 0x70, 0x61, 0x72, 0x74, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, - 0x6f, 0x6c, 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x90, 0x01, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x73, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6f, - 0x70, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x02, 0x52, 0x0c, 0x6f, 0x70, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, - 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x28, 0x0a, 0x10, - 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x37, 0x5a, 0x35, 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, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x52, 0x06, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x12, 0x44, 0x0a, 0x09, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x42, 0x26, 0xe2, 0xfc, + 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x41, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, + 0x61, 0x63, 0x74, 0x2e, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x73, 0x0a, 0x14, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x5f, 0x70, 0x65, 0x72, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x42, 0x40, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x3a, 0x12, 0x38, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x20, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, + 0x13, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x0f, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, + 0x52, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x68, 0x0a, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, + 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x44, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x3e, 0x12, 0x3c, 0x41, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x65, 0x76, + 0x61, 0x6c, 0x75, 0x61, 0x74, 0x65, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x20, 0x74, 0x6f, + 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x2e, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x6c, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x42, + 0x32, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2c, 0x12, 0x2a, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, + 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x2e, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x4f, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x3b, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x35, 0x12, 0x33, 0x54, 0x68, 0x65, 0x20, 0x74, 0x79, 0x70, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x20, 0x43, 0x61, + 0x6e, 0x20, 0x62, 0x65, 0x20, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x2c, 0x20, 0x45, 0x56, 0x45, + 0x4e, 0x54, 0x2c, 0x20, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x5a, 0x0a, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x29, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x23, + 0x12, 0x21, 0x57, 0x68, 0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x20, 0x67, 0x65, 0x74, 0x73, 0x20, 0x69, 0x74, 0x73, 0x20, 0x64, 0x61, + 0x74, 0x61, 0x2e, 0x52, 0x07, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x6a, 0x0a, 0x07, + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x11, 0x20, 0x03, 0x28, 0x09, 0x42, 0x50, 0xe2, + 0xfc, 0xe3, 0xc4, 0x01, 0x4a, 0x12, 0x48, 0x41, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, + 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, + 0x27, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x56, 0x51, 0x4c, 0x20, 0x74, 0x6f, 0x20, + 0x70, 0x72, 0x65, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x70, 0x72, 0x69, 0x6f, 0x72, 0x20, 0x74, 0x6f, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, + 0x07, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x7b, 0x0a, 0x06, 0x65, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x09, 0x42, 0x63, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x5d, + 0x12, 0x5b, 0x56, 0x51, 0x4c, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, + 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x2e, 0x20, 0x49, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c, 0x20, 0x62, 0x65, 0x20, 0x61, 0x75, 0x74, + 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x20, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x06, 0x65, + 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x6d, 0x0a, 0x07, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x18, 0x0b, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, + 0x65, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x44, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x3e, 0x12, 0x3c, 0x41, + 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x20, + 0x70, 0x6f, 0x73, 0x74, 0x20, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x20, 0x74, 0x68, 0x69, + 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, 0x07, 0x72, 0x65, 0x70, + 0x6f, 0x72, 0x74, 0x73, 0x12, 0x34, 0x0a, 0x0c, 0x63, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0b, 0x63, + 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x03, 0x72, 0x61, + 0x77, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, + 0x1e, 0x54, 0x68, 0x65, 0x20, 0x72, 0x61, 0x77, 0x20, 0x59, 0x41, 0x4d, 0x4c, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, + 0x03, 0x72, 0x61, 0x77, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, + 0x3a, 0x7f, 0xda, 0xfc, 0xe3, 0xc4, 0x01, 0x79, 0x0a, 0x77, 0x41, 0x6e, 0x20, 0x61, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x20, 0x77, 0x72, 0x61, 0x70, 0x73, 0x20, 0x61, 0x20, 0x56, 0x51, + 0x4c, 0x20, 0x71, 0x75, 0x65, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x75, 0x73, 0x61, + 0x62, 0x6c, 0x65, 0x2c, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x65, 0x64, 0x20, + 0x77, 0x61, 0x79, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x20, 0x61, 0x72, + 0x65, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x20, 0x63, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x6e, 0x6f, + 0x74, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x7a, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x6d, + 0x2e, 0x22, 0x3c, 0x0a, 0x13, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x25, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, + 0x82, 0x03, 0x0a, 0x04, 0x54, 0x6f, 0x6f, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, + 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x25, + 0x0a, 0x0e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x5f, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x41, 0x73, 0x73, 0x65, 0x74, 0x52, 0x65, + 0x67, 0x65, 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, + 0x65, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0d, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x66, + 0x69, 0x6c, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x50, 0x61, + 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x61, + 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x69, 0x7a, + 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, + 0x6c, 0x69, 0x7a, 0x65, 0x22, 0x4a, 0x0a, 0x0b, 0x74, 0x68, 0x69, 0x72, 0x64, 0x5f, 0x70, 0x61, + 0x72, 0x74, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x6f, 0x6f, 0x6c, 0x52, + 0x05, 0x74, 0x6f, 0x6f, 0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x22, 0x90, 0x01, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x18, + 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x6f, 0x70, 0x73, 0x5f, + 0x70, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x02, + 0x52, 0x0c, 0x6f, 0x70, 0x73, 0x50, 0x65, 0x72, 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x12, 0x19, + 0x0a, 0x08, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x07, 0x6d, 0x61, 0x78, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, + 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x79, + 0x74, 0x65, 0x73, 0x42, 0x37, 0x5a, 0x35, 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, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1191,35 +1260,37 @@ func file_artifact_proto_rawDescGZIP() []byte { return file_artifact_proto_rawDescData } -var file_artifact_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_artifact_proto_msgTypes = make([]protoimpl.MessageInfo, 11) var file_artifact_proto_goTypes = []interface{}{ - (*ColumnType)(nil), // 0: proto.ColumnType - (*ArtifactParameter)(nil), // 1: proto.ArtifactParameter - (*NotebookSourceCell)(nil), // 2: proto.NotebookSourceCell - (*ArtifactSource)(nil), // 3: proto.ArtifactSource - (*Report)(nil), // 4: proto.Report - (*Artifact)(nil), // 5: proto.Artifact - (*ArtifactDescriptors)(nil), // 6: proto.ArtifactDescriptors - (*Tool)(nil), // 7: proto.Tool - (*ThirdParty)(nil), // 8: proto.third_party - (*Resources)(nil), // 9: proto.Resources + (*ArtifactEnv)(nil), // 0: proto.ArtifactEnv + (*ColumnType)(nil), // 1: proto.ColumnType + (*ArtifactParameter)(nil), // 2: proto.ArtifactParameter + (*NotebookSourceCell)(nil), // 3: proto.NotebookSourceCell + (*ArtifactSource)(nil), // 4: proto.ArtifactSource + (*Report)(nil), // 5: proto.Report + (*Artifact)(nil), // 6: proto.Artifact + (*ArtifactDescriptors)(nil), // 7: proto.ArtifactDescriptors + (*Tool)(nil), // 8: proto.Tool + (*ThirdParty)(nil), // 9: proto.third_party + (*Resources)(nil), // 10: proto.Resources } var file_artifact_proto_depIdxs = []int32{ - 2, // 0: proto.ArtifactSource.notebook:type_name -> proto.NotebookSourceCell - 1, // 1: proto.Report.parameters:type_name -> proto.ArtifactParameter - 9, // 2: proto.Artifact.resources:type_name -> proto.Resources - 7, // 3: proto.Artifact.tools:type_name -> proto.Tool - 1, // 4: proto.Artifact.parameters:type_name -> proto.ArtifactParameter - 3, // 5: proto.Artifact.sources:type_name -> proto.ArtifactSource - 4, // 6: proto.Artifact.reports:type_name -> proto.Report - 0, // 7: proto.Artifact.column_types:type_name -> proto.ColumnType - 5, // 8: proto.ArtifactDescriptors.items:type_name -> proto.Artifact - 7, // 9: proto.third_party.tools:type_name -> proto.Tool - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 0, // 0: proto.NotebookSourceCell.env:type_name -> proto.ArtifactEnv + 3, // 1: proto.ArtifactSource.notebook:type_name -> proto.NotebookSourceCell + 2, // 2: proto.Report.parameters:type_name -> proto.ArtifactParameter + 10, // 3: proto.Artifact.resources:type_name -> proto.Resources + 8, // 4: proto.Artifact.tools:type_name -> proto.Tool + 2, // 5: proto.Artifact.parameters:type_name -> proto.ArtifactParameter + 4, // 6: proto.Artifact.sources:type_name -> proto.ArtifactSource + 5, // 7: proto.Artifact.reports:type_name -> proto.Report + 1, // 8: proto.Artifact.column_types:type_name -> proto.ColumnType + 6, // 9: proto.ArtifactDescriptors.items:type_name -> proto.Artifact + 8, // 10: proto.third_party.tools:type_name -> proto.Tool + 11, // [11:11] is the sub-list for method output_type + 11, // [11:11] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_artifact_proto_init() } @@ -1229,7 +1300,7 @@ func file_artifact_proto_init() { } if !protoimpl.UnsafeEnabled { file_artifact_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ColumnType); i { + switch v := v.(*ArtifactEnv); i { case 0: return &v.state case 1: @@ -1241,7 +1312,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ArtifactParameter); i { + switch v := v.(*ColumnType); i { case 0: return &v.state case 1: @@ -1253,7 +1324,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*NotebookSourceCell); i { + switch v := v.(*ArtifactParameter); i { case 0: return &v.state case 1: @@ -1265,7 +1336,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ArtifactSource); i { + switch v := v.(*NotebookSourceCell); i { case 0: return &v.state case 1: @@ -1277,7 +1348,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Report); i { + switch v := v.(*ArtifactSource); i { case 0: return &v.state case 1: @@ -1289,7 +1360,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Artifact); i { + switch v := v.(*Report); i { case 0: return &v.state case 1: @@ -1301,7 +1372,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ArtifactDescriptors); i { + switch v := v.(*Artifact); i { case 0: return &v.state case 1: @@ -1313,7 +1384,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tool); i { + switch v := v.(*ArtifactDescriptors); i { case 0: return &v.state case 1: @@ -1325,7 +1396,7 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ThirdParty); i { + switch v := v.(*Tool); i { case 0: return &v.state case 1: @@ -1337,6 +1408,18 @@ func file_artifact_proto_init() { } } file_artifact_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ThirdParty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_artifact_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Resources); i { case 0: return &v.state @@ -1355,7 +1438,7 @@ func file_artifact_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_artifact_proto_rawDesc, NumEnums: 0, - NumMessages: 10, + NumMessages: 11, NumExtensions: 0, NumServices: 0, }, diff --git a/artifacts/proto/artifact.proto b/artifacts/proto/artifact.proto index 882a7a511c3..2070be0bf0c 100644 --- a/artifacts/proto/artifact.proto +++ b/artifacts/proto/artifact.proto @@ -6,6 +6,12 @@ package proto; option go_package = "www.velocidex.com/golang/velociraptor/artifacts/proto"; +message ArtifactEnv { + string key = 1; + string value = 2; +} + + message ColumnType { string name = 1; string type = 2; @@ -36,6 +42,7 @@ message ArtifactParameter { message NotebookSourceCell { string template = 1; string type = 2; + repeated ArtifactEnv env = 3; } diff --git a/artifacts/testdata/windows/test.config.yaml b/artifacts/testdata/windows/test.config.yaml index 57ac7735924..369a032280d 100644 --- a/artifacts/testdata/windows/test.config.yaml +++ b/artifacts/testdata/windows/test.config.yaml @@ -141,5 +141,5 @@ Frontend: Datastore: implementation: FileBaseDataStore - filestore_directory: ./artifacts/testdata/server - location: ./artifacts/testdata/server + filestore_directory: ./artifacts/testdata/server/ + location: ./artifacts/testdata/server/ diff --git a/bin/collector_test.go b/bin/collector_test.go index 2f3fd19d338..48edca7e9b3 100644 --- a/bin/collector_test.go +++ b/bin/collector_test.go @@ -22,6 +22,7 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/constants" "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/paths" ) type CollectorTestSuite struct { @@ -109,7 +110,9 @@ func (self *CollectorTestSuite) TestCollector() { // Create a new artifact.. file_store_factory := file_store.GetFileStore(self.config_obj) - fd, err := file_store_factory.WriteFile("/artifact_definitions/Custom/TestArtifactDependent.yaml") + + fd, err := file_store_factory.WriteFile(paths.GetArtifactDefintionPath( + "Custom.TestArtifactDependent")) assert.NoError(self.T(), err) fd.Truncate() @@ -127,7 +130,8 @@ sources: `)) fd.Close() - fd, err = file_store_factory.WriteFile("/artifact_definitions/Custom/TestArtifact.yaml") + fd, err = file_store_factory.WriteFile( + paths.GetArtifactDefintionPath("Custom.TestArtifact")) assert.NoError(self.T(), err) fd.Truncate() diff --git a/bin/debian.go b/bin/debian.go index 127ccfffc50..8c2d8037946 100644 --- a/bin/debian.go +++ b/bin/debian.go @@ -200,14 +200,18 @@ fi # Make the filestore path accessible to the user. mkdir -p '%s' -chown -R velociraptor:velociraptor '%s' /etc/velociraptor/ + +# Only chown two levels of the filestore directory in case +# this is an upgrade and there are many files already there. +chown velociraptor:velociraptor '%s' /etc/velociraptor/ +chown velociraptor:velociraptor '%s/*' /etc/velociraptor/ chmod -R go-r /etc/velociraptor/ chmod o+x /usr/local/bin/velociraptor /usr/local/bin/velociraptor.bin setcap CAP_SYS_RESOURCE,CAP_NET_BIND_SERVICE=+eip /usr/local/bin/velociraptor.bin /bin/systemctl enable velociraptor_server /bin/systemctl start velociraptor_server -`, filestore_path, filestore_path)) +`, filestore_path, filestore_path, filestore_path)) kingpin.FatalIfError(err, "Adding file") err = deb.AddControlExtraString("prerm", ` diff --git a/bin/fs.go b/bin/fs.go index 9ec23942f36..5e7862d5533 100644 --- a/bin/fs.go +++ b/bin/fs.go @@ -30,6 +30,7 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/file_store" "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/glob" logging "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/reporting" @@ -252,10 +253,11 @@ func doCp(path, accessor string, dump_dir string) { } case "fs": + output_path_spec := path_specs.NewSafeFilestorePath(output_path) builder.Uploader = api.NewFileStoreUploader( config_obj, file_store.GetFileStore(config_obj), - output_path) + output_path_spec) default: kingpin.Fatalf("Can not write to accessor %v\n", output_accessor) diff --git a/bin/golden.go b/bin/golden.go index f336d7dc0c0..8295c492818 100644 --- a/bin/golden.go +++ b/bin/golden.go @@ -61,7 +61,8 @@ var ( golden_env_map = golden_command.Flag("env", "Environment for the query."). StringMap() - testonly = golden_command.Flag("testonly", "Do not update the fixture.").Bool() + testonly = golden_command.Flag("testonly", "Do not update the fixture.").Bool() + disable_alarm = golden_command.Flag("disable_alarm", "Do not terminate when deadlocked.").Bool() ) type testFixture struct { @@ -138,8 +139,13 @@ func makeCtxWithTimeout(duration int) (context.Context, func()) { func runTest(fixture *testFixture, sm *services.Service, config_obj *config_proto.Config) (string, error) { - ctx, cancel := makeCtxWithTimeout(30) - defer cancel() + ctx := context.Background() + if !*disable_alarm { + sub_ctx, cancel := makeCtxWithTimeout(30) + defer cancel() + + ctx = sub_ctx + } // Create an output container. tmpfile, err := ioutil.TempFile("", "golden") @@ -223,8 +229,10 @@ func runTest(fixture *testFixture, sm *services.Service, func doGolden() { vql_subsystem.RegisterPlugin(&MemoryLogPlugin{}) - _, cancel := makeCtxWithTimeout(120) - defer cancel() + if !*disable_alarm { + _, cancel := makeCtxWithTimeout(120) + defer cancel() + } config_obj, err := makeDefaultConfigLoader().LoadAndValidate() kingpin.FatalIfError(err, "Can not load configuration.") diff --git a/config/config.go b/config/config.go index 743577bb5ed..f387264af49 100644 --- a/config/config.go +++ b/config/config.go @@ -153,8 +153,8 @@ func GetDefaultConfig() *config_proto.Config { // Users would probably need to change // this to something more permanent. - Location: "/var/tmp/velociraptor", - FilestoreDirectory: "/var/tmp/velociraptor", + Location: "/var/tmp/velociraptor/", + FilestoreDirectory: "/var/tmp/velociraptor/", }, Writeback: &config_proto.Writeback{}, Mail: &config_proto.MailConfig{}, diff --git a/config/migration.go b/config/migration.go index 7f06f0d07b2..2959746c2fc 100644 --- a/config/migration.go +++ b/config/migration.go @@ -4,6 +4,7 @@ import ( "crypto/sha256" "encoding/hex" "regexp" + "strings" config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/logging" @@ -160,8 +161,27 @@ func migrate_0_5_6(config_obj *config_proto.Config) { } } +func migrate_0_6_1(config_obj *config_proto.Config) { + // We require the datastore location to have no trailing path + // separators. + if config_obj.Datastore != nil { + config_obj.Datastore.Location = strings.TrimSuffix( + config_obj.Datastore.Location, "\\") + + config_obj.Datastore.Location = strings.TrimSuffix( + config_obj.Datastore.Location, "/") + + config_obj.Datastore.FilestoreDirectory = strings.TrimSuffix( + config_obj.Datastore.FilestoreDirectory, "\\") + + config_obj.Datastore.FilestoreDirectory = strings.TrimSuffix( + config_obj.Datastore.FilestoreDirectory, "/") + } +} + func migrate(config_obj *config_proto.Config) { migrate_0_4_2(config_obj) migrate_0_4_6(config_obj) migrate_0_5_6(config_obj) + migrate_0_6_1(config_obj) } diff --git a/constants/constants.go b/constants/constants.go index f5fd022d3ab..3fc8a1886b6 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -31,17 +31,6 @@ const ( FOREMAN_WELL_KNOWN_FLOW = "E.Foreman" HUNT_PREFIX = "H." - // The GUI uses this as the client index. - CLIENT_INDEX_URN = "/client_index/" - - // An index of all the hunts and clients. - HUNT_INDEX = "/hunt_index/" - NOTEBOOK_INDEX = "/notebook_index/" - USER_URN = "/users/" - - // Timelines - TIMELINE_URN = "/timelines/" - // Well known flows - Request ID: LOG_SINK uint64 = 980 @@ -52,18 +41,9 @@ const ( MAX_MEMORY = 5 * 1024 * 1024 MAX_POST_SIZE = 5 * 1024 * 1024 - // Filestore paths for artifacts must begin with this prefix. - ARTIFACT_DEFINITION_PREFIX = "/artifact_definitions/" - // Messages to the client which we dont care about their responses. IgnoreResponseState = uint64(101) - // These store configuration for the server and client - // monitoring artifacts. - ServerMonitoringFlowURN = "/config/server_monitoring.json" - ClientMonitoringFlowURN = "/config/client_monitoring.json" - ThirdPartyInventory = "/config/inventory.json" - USER_AGENT = "Velociraptor - Dig Deeper!" // Internal artifact names. diff --git a/crypto/server/manager.go b/crypto/server/manager.go index 94e5a4fef7b..36ae3d68e4e 100644 --- a/crypto/server/manager.go +++ b/crypto/server/manager.go @@ -124,7 +124,7 @@ func (self *serverPublicKeyResolver) GetPublicKey( pem := &crypto_proto.PublicKey{} err = db.GetSubject(self.config_obj, - client_path_manager.Key().Path(), pem) + client_path_manager.Key(), pem) if err != nil { return nil, false } @@ -151,7 +151,7 @@ func (self *serverPublicKeyResolver) SetPublicKey( EnrollTime: uint64(time.Now().Unix()), } return db.SetSubject(self.config_obj, - client_path_manager.Key().Path(), pem) + client_path_manager.Key(), pem) } func (self *serverPublicKeyResolver) Clear() {} diff --git a/datastore/datastore.go b/datastore/datastore.go index a41ffd3168c..20427297d3a 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -20,11 +20,14 @@ package datastore import ( "errors" + "strings" "sync" + "time" "google.golang.org/protobuf/proto" config_proto "www.velocidex.com/golang/velociraptor/config/proto" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" ) var ( @@ -39,7 +42,13 @@ const ( SORT_DOWN = SortingSense(2) ) -type WalkFunc func(urn string) error +type DatastoreInfo struct { + Name string + Modified time.Time +} + +type WalkFunc func(urn api.DSPathSpec) error +type ComponentWalkFunc func(components api.DSPathSpec) error type DataStore interface { // Retrieve all the client's tasks. @@ -63,50 +72,50 @@ type DataStore interface { // os.ErrNotExist error. GetSubject( config_obj *config_proto.Config, - urn string, + urn api.DSPathSpec, message proto.Message) error SetSubject( config_obj *config_proto.Config, - urn string, + urn api.DSPathSpec, message proto.Message) error DeleteSubject( config_obj *config_proto.Config, - urn string) error + urn api.DSPathSpec) error // Lists all the children of a URN. ListChildren( config_obj *config_proto.Config, - urn string, - offset uint64, length uint64) ([]string, error) + urn api.DSPathSpec, + offset uint64, length uint64) ([]api.DSPathSpec, error) Walk(config_obj *config_proto.Config, - root string, walkFn WalkFunc) error + root api.DSPathSpec, walkFn WalkFunc) error // Update the posting list index. Searching for any of the // keywords will return the entity urn. SetIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error UnsetIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error CheckIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error SearchClients( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, query string, query_type string, offset uint64, limit uint64, sort SortingSense) []string @@ -121,12 +130,24 @@ func GetDB(config_obj *config_proto.Config) (DataStore, error) { switch config_obj.Datastore.Implementation { case "FileBaseDataStore": + if config_obj.Datastore.Location == "" { + return nil, errors.New( + "No Datastore_location is set in the config.") + } + return file_based_imp, nil case "Test": mu.Lock() defer mu.Unlock() + // Sanitize the FilestoreDirectory parameter so we + // have a consistent filename in the test datastore. + config_obj.Datastore.Location = strings.TrimSuffix( + config_obj.Datastore.Location, "/") + config_obj.Datastore.Location = strings.TrimSuffix( + config_obj.Datastore.Location, "\\") + return gTestDatastore, nil default: diff --git a/datastore/datastore_test.go b/datastore/datastore_test.go index c9d89b468e3..0875a7366d4 100644 --- a/datastore/datastore_test.go +++ b/datastore/datastore_test.go @@ -11,8 +11,28 @@ import ( "github.com/stretchr/testify/suite" "google.golang.org/protobuf/proto" config_proto "www.velocidex.com/golang/velociraptor/config/proto" - "www.velocidex.com/golang/velociraptor/constants" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" + "www.velocidex.com/golang/velociraptor/paths" + "www.velocidex.com/golang/velociraptor/utils" +) + +var ( + testPaths = []struct { + urn api.DSPathSpec + path string + }{ + // This one should be safe + {path_specs.NewSafeDatastorePath("a", "b", "c"), "/a/b/c.db"}, + + // Path components are actually a list of strings. + {path_specs.NewUnsafeDatastorePath("a", "b/c", "d"), + "/a/b%2Fc/d.db"}, + + {path_specs.NewUnsafeDatastorePath("a", "b/c", "d/d"), + "/a/b%2Fc/d%2Fd.db"}, + } ) type BaseTestSuite struct { @@ -22,10 +42,85 @@ type BaseTestSuite struct { datastore DataStore } +func (self BaseTestSuite) TestSetGetJSON() { + message := &crypto_proto.VeloMessage{Source: "Server"} + for _, path := range []path_specs.DSPathSpec{ + path_specs.NewUnsafeDatastorePath("a", "b/c", "d"), + path_specs.NewUnsafeDatastorePath("a", "b/c", "d/a"), + path_specs.NewUnsafeDatastorePath("a", "b/c", "d?\""), + } { + err := self.datastore.SetSubject( + self.config_obj, path, message) + assert.NoError(self.T(), err) + + read_message := &crypto_proto.VeloMessage{} + err = self.datastore.GetSubject(self.config_obj, + path, read_message) + assert.NoError(self.T(), err) + + assert.Equal(self.T(), message.Source, read_message.Source) + } + + // Now test that ListChildren works properly. + children, err := self.datastore.ListChildren( + self.config_obj, path_specs.NewUnsafeDatastorePath("a", "b/c"), + 0, 100) + assert.NoError(self.T(), err) + + results := []string{} + for _, i := range children { + results = append(results, i.Base()) + } + sort.Strings(results) + assert.Equal(self.T(), []string{"d", "d/a", "d?\""}, results) +} + +// Old server versions might have data encoded in protobufs. As we +// port new data to json, we need to support reading the old data +// properly. +func (self BaseTestSuite) TestSetGetMigration() { + message := &crypto_proto.VeloMessage{Source: "Server"} + for _, path := range []path_specs.DSPathSpec{ + path_specs.NewUnsafeDatastorePath("a", "b", "c"), + } { + // Write a protobuf based file + urn := path_specs.NewSafeDatastorePath(path.Components()...). + SetType(api.PATH_TYPE_DATASTORE_PROTO) + err := self.datastore.SetSubject( + self.config_obj, urn, message) + assert.NoError(self.T(), err) + + // Even if we read it with json it should work. + read_message := &crypto_proto.VeloMessage{} + err = self.datastore.GetSubject(self.config_obj, + path.SetType(api.PATH_TYPE_DATASTORE_JSON), read_message) + assert.NoError(self.T(), err) + + assert.Equal(self.T(), message.Source, read_message.Source) + } +} + +func (self BaseTestSuite) TestSetGetSubjectWithEscaping() { + message := &crypto_proto.VeloMessage{Source: "Server"} + for _, testcase := range testPaths { + err := self.datastore.SetSubject( + self.config_obj, testcase.urn, message) + assert.NoError(self.T(), err) + + read_message := &crypto_proto.VeloMessage{} + err = self.datastore.GetSubject(self.config_obj, + testcase.urn, read_message) + assert.NoError(self.T(), err) + + assert.Equal(self.T(), message.Source, read_message.Source) + } +} + func (self BaseTestSuite) TestSetGetSubject() { message := &crypto_proto.VeloMessage{Source: "Server"} - urn := "/a/b/c" + urn := path_specs.NewSafeDatastorePath("a", "b", "c"). + SetType(api.PATH_TYPE_DATASTORE_PROTO) err := self.datastore.SetSubject(self.config_obj, urn, message) assert.NoError(self.T(), err) @@ -37,13 +132,16 @@ func (self BaseTestSuite) TestSetGetSubject() { // Not existing urn returns os.ErrNotExist error and an empty message read_message.SessionId = "X" - err = self.datastore.GetSubject(self.config_obj, urn+"foo", read_message) + err = self.datastore.GetSubject(self.config_obj, + urn.AddChild("foo"), read_message) assert.Error(self.T(), err, os.ErrNotExist) // Same for json files. read_message.SessionId = "X" err = self.datastore.GetSubject( - self.config_obj, urn+"foo.json", read_message) + self.config_obj, urn.AddChild("foo"). + SetType(api.PATH_TYPE_DATASTORE_JSON), + read_message) assert.Error(self.T(), err, os.ErrNotExist) // Delete the subject @@ -58,68 +156,79 @@ func (self BaseTestSuite) TestSetGetSubject() { func (self BaseTestSuite) TestListChildren() { message := &crypto_proto.VeloMessage{Source: "Server"} - urn := "/a/b/c" - err := self.datastore.SetSubject(self.config_obj, urn+"/1", message) + urn := path_specs.NewSafeDatastorePath("a", "b", "c") + err := self.datastore.SetSubject(self.config_obj, + urn.AddChild("1"), message) assert.NoError(self.T(), err) time.Sleep(10 * time.Millisecond) - err = self.datastore.SetSubject(self.config_obj, urn+"/2", message) + err = self.datastore.SetSubject(self.config_obj, + urn.AddChild("2"), message) assert.NoError(self.T(), err) time.Sleep(10 * time.Millisecond) - err = self.datastore.SetSubject(self.config_obj, urn+"/3", message) + err = self.datastore.SetSubject(self.config_obj, + urn.AddChild("3"), message) assert.NoError(self.T(), err) time.Sleep(10 * time.Millisecond) - children, err := self.datastore.ListChildren(self.config_obj, urn, 0, 100) + children, err := self.datastore.ListChildren( + self.config_obj, urn, 0, 100) assert.NoError(self.T(), err) // ListChildren gives the full path to all children - sort.Strings(children) assert.Equal(self.T(), []string{ "/a/b/c/1", "/a/b/c/2", - "/a/b/c/3"}, children) + "/a/b/c/3"}, asStrings(children)) - children, err = self.datastore.ListChildren(self.config_obj, urn, 0, 2) + children, err = self.datastore.ListChildren(self.config_obj, + urn, 0, 2) assert.NoError(self.T(), err) - assert.Equal(self.T(), []string{"/a/b/c/1", "/a/b/c/2"}, children) + assert.Equal(self.T(), []string{"/a/b/c/1", "/a/b/c/2"}, + asStrings(children)) - children, err = self.datastore.ListChildren(self.config_obj, urn, 1, 2) + children, err = self.datastore.ListChildren(self.config_obj, + urn, 1, 2) assert.NoError(self.T(), err) - assert.Equal(self.T(), []string{"/a/b/c/2", "/a/b/c/3"}, children) + assert.Equal(self.T(), []string{"/a/b/c/2", "/a/b/c/3"}, + asStrings(children)) - visited := []string{} - self.datastore.Walk(self.config_obj, "/\"a\"/b", - func(path_name string) error { + visited := []api.DSPathSpec{} + self.datastore.Walk(self.config_obj, + path_specs.NewSafeDatastorePath("a", "b"), + func(path_name api.DSPathSpec) error { visited = append(visited, path_name) return nil }) - sort.Strings(visited) - assert.Equal(self.T(), []string{"/a/b/c/1", "/a/b/c/2", "/a/b/c/3"}, visited) + assert.Equal(self.T(), []string{ + "/a/b/c/1", + "/a/b/c/2", + "/a/b/c/3"}, + asStrings(visited)) } func (self BaseTestSuite) TestIndexes() { client_id := "C.1234" client_id_2 := "C.1235" - err := self.datastore.SetIndex(self.config_obj, constants.CLIENT_INDEX_URN, + err := self.datastore.SetIndex(self.config_obj, paths.CLIENT_INDEX_URN, client_id, []string{"all", client_id, "Hostname", "FQDN", "host:Foo"}) assert.NoError(self.T(), err) - err = self.datastore.SetIndex(self.config_obj, constants.CLIENT_INDEX_URN, + err = self.datastore.SetIndex(self.config_obj, paths.CLIENT_INDEX_URN, client_id_2, []string{"all", client_id_2, "Hostname2", "FQDN2", "host:Bar"}) assert.NoError(self.T(), err) - hits := self.datastore.SearchClients(self.config_obj, constants.CLIENT_INDEX_URN, - "all", "", 0, 100, SORT_UP) + hits := self.datastore.SearchClients(self.config_obj, + paths.CLIENT_INDEX_URN, "all", "", 0, 100, SORT_UP) sort.Strings(hits) assert.Equal(self.T(), []string{client_id, client_id_2}, hits) - hits = self.datastore.SearchClients(self.config_obj, constants.CLIENT_INDEX_URN, + hits = self.datastore.SearchClients(self.config_obj, paths.CLIENT_INDEX_URN, "*foo", "", 0, 100, SORT_UP) assert.Equal(self.T(), []string{client_id}, hits) } @@ -186,3 +295,14 @@ func benchmarkSearchClient(b *testing.B, config_obj *config_proto.Config) { } + +func asStrings(in []api.DSPathSpec) []string { + children := make([]string, 0, len(in)) + for _, i := range in { + children = append(children, utils.JoinComponents( + i.Components(), "/")) + } + sort.Strings(children) + + return children +} diff --git a/datastore/filebased.go b/datastore/filebased.go index 45ffb26df67..a72940b0eb4 100644 --- a/datastore/filebased.go +++ b/datastore/filebased.go @@ -55,6 +55,8 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/constants" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/utils" @@ -83,23 +85,15 @@ func (self *FileBaseDataStore) GetClientTasks( client_id string, do_not_lease bool) ([]*crypto_proto.VeloMessage, error) { result := []*crypto_proto.VeloMessage{} - now := self.currentTaskId() client_path_manager := paths.NewClientPathManager(client_id) - now_urn := client_path_manager.Task(now).Path() - tasks, err := self.ListChildren( - config_obj, client_path_manager.TasksDirectory().Path(), 0, 100) + config_obj, client_path_manager.TasksDirectory(), 0, 100) if err != nil { return nil, err } for _, task_urn := range tasks { - // Only read until the current timestamp. - if task_urn > now_urn { - break - } - // Here we read the task from the task_urn and remove // it from the queue. message := &crypto_proto.VeloMessage{} @@ -126,7 +120,7 @@ func (self *FileBaseDataStore) UnQueueMessageForClient( client_path_manager := paths.NewClientPathManager(client_id) return self.DeleteSubject(config_obj, - client_path_manager.Task(message.TaskId).Path()) + client_path_manager.Task(message.TaskId)) } func (self *FileBaseDataStore) currentTaskId() uint64 { @@ -144,28 +138,44 @@ func (self *FileBaseDataStore) QueueMessageForClient( client_path_manager := paths.NewClientPathManager(client_id) return self.SetSubject(config_obj, - client_path_manager.Task(req.TaskId).Path(), req) + client_path_manager.Task(req.TaskId), req) } /* Gets a protobuf encoded struct from the data store. Objects are addressed by the urn which is a string (URNs are typically managed by a path manager) - - FIXME: Refactor GetSubject to accept path manager directly. */ func (self *FileBaseDataStore) GetSubject( config_obj *config_proto.Config, - urn string, + urn api.DSPathSpec, message proto.Message) error { serialized_content, err := readContentFromFile( config_obj, urn, true /* must_exist */) if err != nil { - return errors.WithMessage(os.ErrNotExist, - fmt.Sprintf("While openning %v: %v", urn, err)) + // Second try the old DB without json. This support + // migration from old protobuf based datastore files + // to newer json based blobs while still being able to + // read old files. + if urn.Type() == api.PATH_TYPE_DATASTORE_JSON { + serialized_content, err = readContentFromFile( + config_obj, + urn.SetType(api.PATH_TYPE_DATASTORE_PROTO), + true /* must_exist */) + } + if err != nil { + return errors.WithMessage(os.ErrNotExist, + fmt.Sprintf("While openning %v: %v", + urn.AsClientPath(), err)) + } + } + + if len(serialized_content) == 0 { + return nil } - if strings.HasSuffix(urn, ".json") { + // It is really a JSON blob + if serialized_content[0] == '{' { err = protojson.Unmarshal(serialized_content, message) } else { err = proto.Unmarshal(serialized_content, message) @@ -179,46 +189,47 @@ func (self *FileBaseDataStore) GetSubject( } func (self *FileBaseDataStore) Walk(config_obj *config_proto.Config, - root string, walkFn WalkFunc) error { - root_path, err := urnToFilename(config_obj, root) + root api.DSPathSpec, walkFn WalkFunc) error { + all_children, err := listChildren(config_obj, root) if err != nil { return err } - root_path = strings.TrimSuffix(root_path, ".db") - - return filepath.Walk(root_path, - func(path string, info os.FileInfo, err error) error { + for _, child := range all_children { + name := child.Name() + // Recurse into directories + if child.IsDir() { + err := self.Walk( + config_obj, + root.AddChild(utils.UnsanitizeComponent( + name)), walkFn) if err != nil { - return err - } - - if info.IsDir() { - return nil - } - - // We are only interested in filenames that end with .db - basename := info.Name() - if !strings.HasSuffix(basename, ".db") { - return nil + // Do not quit the walk early. } - urn, err := FilenameToURN(config_obj, path) - if err != nil { - return err + } else { + // If the filename ends with .db then it is + // part of the data store. + if strings.HasSuffix(name, ".db") { + name = strings.TrimSuffix(name, ".db") + name = strings.TrimSuffix(name, ".json") + walkFn(root.AddChild( + utils.UnsanitizeComponent(name))) + continue } + } + } - return walkFn(urn) - }) + return nil } func (self *FileBaseDataStore) SetSubject( config_obj *config_proto.Config, - urn string, + urn api.DSPathSpec, message proto.Message) error { // Encode as JSON - if strings.HasSuffix(urn, ".json") { + if urn.Type() == api.PATH_TYPE_DATASTORE_JSON { serialized_content, err := protojson.Marshal(message) if err != nil { return err @@ -235,13 +246,9 @@ func (self *FileBaseDataStore) SetSubject( func (self *FileBaseDataStore) DeleteSubject( config_obj *config_proto.Config, - urn string) error { + urn api.DSPathSpec) error { - filename, err := urnToFilename(config_obj, urn) - if err != nil { - return err - } - err = os.Remove(filename) + err := os.Remove(urn.AsDatastoreFilename(config_obj)) // It is ok to remove a file that does not exist. if err != nil && os.IsExist(err) { @@ -253,24 +260,17 @@ func (self *FileBaseDataStore) DeleteSubject( return nil } -func listChildNames(config_obj *config_proto.Config, urn string) ( +func listChildNames(config_obj *config_proto.Config, + urn api.DSPathSpec) ( []string, error) { - filename, err := urnToFilename(config_obj, urn) - if err != nil { - return nil, err - } - dirname := strings.TrimSuffix(filename, ".db") - return utils.ReadDirNames(dirname) + return utils.ReadDirNames( + urn.AsDatastoreDirectory(config_obj)) } func listChildren(config_obj *config_proto.Config, - urn string) ([]os.FileInfo, error) { - filename, err := urnToFilename(config_obj, urn) - if err != nil { - return nil, err - } - dirname := strings.TrimSuffix(filename, ".db") - children, err := utils.ReadDirUnsorted(dirname) + urn api.DSPathSpec) ([]os.FileInfo, error) { + children, err := utils.ReadDirUnsorted( + urn.AsDatastoreDirectory(config_obj)) if err != nil { if os.IsNotExist(err) { return []os.FileInfo{}, nil @@ -283,8 +283,9 @@ func listChildren(config_obj *config_proto.Config, // Lists all the children of a URN. func (self *FileBaseDataStore) ListChildren( config_obj *config_proto.Config, - urn string, - offset uint64, length uint64) ([]string, error) { + urn api.DSPathSpec, + offset uint64, length uint64) ( + []api.DSPathSpec, error) { all_children, err := listChildren(config_obj, urn) if err != nil { return nil, err @@ -306,17 +307,18 @@ func (self *FileBaseDataStore) ListChildren( }) // Slice the result according to the required offset and count. - result := make([]string, 0, len(children)) - urn = strings.TrimSuffix(urn, "/") + result := make([]api.DSPathSpec, 0, len(children)) for i := offset; i < offset+length; i++ { if i >= uint64(len(children)) { break } - name := UnsanitizeComponent(children[i].Name()) + // Strip data store extensions + name := children[i].Name() name = strings.TrimSuffix(name, ".db") name = strings.TrimSuffix(name, ".json") - result = append(result, utils.PathJoin(urn, name, "/")) + result = append(result, + urn.AddChild(utils.UnsanitizeComponent(name))) } return result, nil @@ -326,12 +328,17 @@ func (self *FileBaseDataStore) ListChildren( // keywords will return the entity urn. func (self *FileBaseDataStore) SetIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error { + entity = utils.SanitizeString(entity) + for _, keyword := range keywords { - subject := path.Join(index_urn, strings.ToLower(keyword), entity) + // The entity and keywords are not trusted because + // they are user provided. + keyword = utils.SanitizeString(strings.ToLower(keyword)) + subject := index_urn.AddChild(keyword, entity) err := self.SetSubject(config_obj, subject, &empty.Empty{}) if err != nil { return err @@ -342,12 +349,15 @@ func (self *FileBaseDataStore) SetIndex( func (self *FileBaseDataStore) UnsetIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error { + entity = utils.SanitizeString(entity) + for _, keyword := range keywords { - subject := path.Join(index_urn, strings.ToLower(keyword), entity) + keyword = utils.SanitizeString(strings.ToLower(keyword)) + subject := index_urn.AddChild(keyword, entity) err := self.DeleteSubject(config_obj, subject) if err != nil { return err @@ -358,11 +368,15 @@ func (self *FileBaseDataStore) UnsetIndex( func (self *FileBaseDataStore) CheckIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error { + + entity = utils.SanitizeString(entity) + for _, keyword := range keywords { - subject := path.Join(index_urn, strings.ToLower(keyword), entity) + keyword = utils.SanitizeString(strings.ToLower(keyword)) + subject := index_urn.AddChild(keyword, entity) _, err := readContentFromFile( config_obj, subject, true /* must_exist */) // Any of the matching entities means we checked @@ -376,7 +390,7 @@ func (self *FileBaseDataStore) CheckIndex( func (self *FileBaseDataStore) SearchClients( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, query string, query_type string, offset uint64, limit uint64, sort_direction SortingSense) []string { @@ -403,18 +417,18 @@ func (self *FileBaseDataStore) SearchClients( } add_func := func(key string) { - children, err := listChildNames( - config_obj, path.Join(index_urn, key)) + children, err := listChildNames(config_obj, + index_urn.AddChild(utils.SanitizeString(key))) if err != nil { return } - for _, child_urn := range children { - name := UnsanitizeComponent(child_urn) - name = strings.TrimSuffix(name, ".db") - _, pres := seen[name] + for _, child_name := range children { + _, pres := seen[child_name] if !pres { - seen[name] = true + seen[child_name] = true + name := utils.UnsanitizeComponent(child_name) + name = strings.TrimSuffix(name, ".db") result = append(result, name) } @@ -438,7 +452,7 @@ func (self *FileBaseDataStore) SearchClients( } for _, set := range sets { - name := UnsanitizeComponent(set) + name := utils.UnsanitizeComponent(set) name = strings.TrimSuffix(name, ".db") matched, err := path.Match(query, name) if err != nil { @@ -497,127 +511,12 @@ func (self *FileBaseDataStore) SearchClients( // Called to close all db handles etc. Not thread safe. func (self *FileBaseDataStore) Close() {} -var hexTable = []rune("0123456789ABCDEF") +func writeContentToFile(config_obj *config_proto.Config, + urn api.DSPathSpec, data []byte) error { -// We are very conservative about our escaping. -func shouldEscape(c byte) bool { - if 'A' <= c && c <= 'Z' || - 'a' <= c && c <= 'z' || - '0' <= c && c <= '9' { - return false - } - - switch c { - case '-', '_', '.', '~', ' ', '$': - return false - } - - return true -} - -func SanitizeString(component string) []rune { - // Escape components that start with . - these are illegal on - // windows. - if len(component) > 0 && component[0:1] == "." { - return []rune("%2E" + component[1:]) - } - - // Prevent components from creating names for files that are - // used internally by the datastore. - if strings.HasSuffix(component, ".db") { - component += "_" - } - - length := len(component) - if length > 1024 { - length = 1024 - } - - result := make([]rune, length*4) - result_idx := 0 - - for _, c := range []byte(component) { - if !shouldEscape(c) { - result[result_idx] = rune(c) - result_idx += 1 - } else { - result[result_idx] = '%' - result[result_idx+1] = hexTable[c>>4] - result[result_idx+2] = hexTable[c&15] - result_idx += 3 - } - } - return result[:result_idx] -} - -func unhex(c rune) rune { - switch { - case '0' <= c && c <= '9': - return c - '0' - case 'a' <= c && c <= 'f': - return c - 'a' + 10 - case 'A' <= c && c <= 'F': - return c - 'A' + 10 - } - return 0 -} - -func UnsanitizeComponent(component_str string) string { - component := []rune(component_str) - result := "" - i := 0 - for { - if i >= len(component) { - return result - } - - if component[i] == '%' { - c := unhex(component[i+1])<<4 | unhex(component[i+2]) - result += string(c) - i += 3 - } else { - result += string(component[i]) - i += 1 - } - } -} - -func urnToFilename(config_obj *config_proto.Config, urn string) (string, error) { - if config_obj.Datastore == nil || - config_obj.Datastore.Location == "" { - return "", errors.New("No Datastore_location is set in the config.") - } - - components := []string{config_obj.Datastore.Location} - for _, component := range utils.SplitComponents(urn) { - components = append(components, string(SanitizeString(component))) - } - - // Files all end with .db. Note a component can never have - // this suffix so it is not possible to break the datastore by - // having a urn with a component that ends with .db which - // creates a directory with the same name as a file. - result := filepath.Join(components...) + ".db" - - // This relies on the filepath starting with a drive letter - // and having \ as path separators. Main's - // validateServerConfig() ensures this is the case. - if runtime.GOOS == "windows" { - return "\\\\?\\" + result, nil - } - - // fmt.Printf("Accessing on %v\n", result) - - return result, nil -} - -func writeContentToFile(config_obj *config_proto.Config, urn string, data []byte) error { - filename, err := urnToFilename(config_obj, urn) - if err != nil { - return err - } - - file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0660) + filename := urn.AsDatastoreFilename(config_obj) + file, err := os.OpenFile( + filename, os.O_RDWR|os.O_CREATE, 0660) // Try to create intermediate directories and try again. if err != nil && os.IsNotExist(err) { @@ -632,7 +531,7 @@ func writeContentToFile(config_obj *config_proto.Config, urn string, data []byte } if err != nil { logging.GetLogger(config_obj, &logging.FrontendComponent).Error( - "Unable to open file "+filename, err) + "Unable to open file %v: %v", filename, err) return errors.WithStack(err) } defer file.Close() @@ -650,14 +549,9 @@ func writeContentToFile(config_obj *config_proto.Config, urn string, data []byte } func readContentFromFile( - config_obj *config_proto.Config, urn string, + config_obj *config_proto.Config, urn api.DSPathSpec, must_exist bool) ([]byte, error) { - filename, err := urnToFilename(config_obj, urn) - if err != nil { - return nil, err - } - - file, err := os.Open(filename) + file, err := os.Open(urn.AsDatastoreFilename(config_obj)) if err == nil { defer file.Close() @@ -673,25 +567,30 @@ func readContentFromFile( return nil, errors.WithStack(err) } -// Convert a file name from the data store to a urn. -func FilenameToURN(config_obj *config_proto.Config, filename string) (string, error) { +// Convert a file name from the data store to a DSPathSpec +func FilenameToURN(config_obj *config_proto.Config, + filename string) api.DSPathSpec { if runtime.GOOS == "windows" { filename = strings.TrimPrefix(filename, WINDOWS_LFN_PREFIX) } - filename = strings.TrimPrefix( - filename, config_obj.Datastore.FilestoreDirectory) + filename = strings.TrimPrefix(filename, config_obj.Datastore.Location) components := []string{} + // DS filenames are always clean so a strings split is fine. for _, component := range strings.Split( - filename, - string(os.PathSeparator)) { - component = strings.TrimSuffix(component, ".db") - components = append(components, - string(UnsanitizeComponent(component))) + filename, string(os.PathSeparator)) { + if component != "" { + components = append(components, component) + } } - // Filestore filenames always use / as separator. - result := utils.JoinComponents(components, "/") - return result, nil + // Strip any extension from the last component. + if len(components) > 0 { + last := len(components) - 1 + components[last] = strings.TrimPrefix( + strings.TrimSuffix(components[last], ".db"), ".json") + } + + return path_specs.NewSafeDatastorePath(components...) } diff --git a/datastore/filebased_benchmark_test.go b/datastore/filebased_benchmark_test.go index c433590ab83..f7ab8d41c5a 100644 --- a/datastore/filebased_benchmark_test.go +++ b/datastore/filebased_benchmark_test.go @@ -29,7 +29,7 @@ func BenchmarkSetSubject(b *testing.B) { ClientId: client_id, } db.SetSubject(config_obj, - client_path_manager.Ping().Path(), client_info) + client_path_manager.Ping(), client_info) } }) diff --git a/datastore/filebased_json.go b/datastore/filebased_json.go new file mode 100644 index 00000000000..97ecdae0416 --- /dev/null +++ b/datastore/filebased_json.go @@ -0,0 +1,97 @@ +/* + The new style API: + + 1. Paths are treated as a list of components (no need for callers to + worry about escaping). + + 2. All data is written out in JSON. Although protobufs are more + compact, JSON is easier to work with and the space saving is not + significant (the datastore only stores very small files). + + The old style API uses URNs as strings that are converted back and + forth from components. This will eventually be deprecated. +*/ + +package datastore + +import ( + "os" + "path/filepath" + "strings" + + config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/utils" +) + +// List a directory on disk and produce a list of valid data store +// files contained within the directory. +func (self *FileBaseDataStore) ListChildrenJSON( + config_obj *config_proto.Config, + path api.DSPathSpec) ([]*DatastoreInfo, error) { + + dirpath := path.AsDatastoreDirectory(config_obj) + child_names, err := utils.ReadDirNames(dirpath) + if err != nil { + return nil, err + } + + result := make([]*DatastoreInfo, 0, len(child_names)) + for _, name := range child_names { + if !strings.HasSuffix(name, ".json.db") { + continue + } + + s, err := os.Lstat(filepath.Join(dirpath, name)) + if err != nil { + continue + } + + // Unsanitize the component from a filename to + // a component name. + component := utils.UnsanitizeComponent( + strings.TrimSuffix(name, ".json.db")) + result = append(result, &DatastoreInfo{ + Name: component, + Modified: s.ModTime(), + }) + } + + return result, nil +} + +func (self *FileBaseDataStore) WalkComponents( + config_obj *config_proto.Config, + root_components api.DSPathSpec, walkFn ComponentWalkFunc) error { + + dirname := root_components.AsDatastoreDirectory(config_obj) + names, err := utils.ReadDirNames(dirname) + if err != nil { + return err + } + + for _, name := range names { + s, err := os.Lstat(filepath.Join(dirname, name)) + if err != nil { + continue + } + + next_name := utils.UnsanitizeComponent(name) + next_components := root_components.AddChild(next_name) + + // If it is a directory walk it as well. + if s.IsDir() { + err = self.WalkComponents(config_obj, + next_components, walkFn) + if err == filepath.SkipDir { + return err + } + } + + err = walkFn(next_components) + if err == filepath.SkipDir { + return err + } + } + return nil +} diff --git a/datastore/filebased_test.go b/datastore/filebased_test.go index dd8dc39e6c8..2ec5942d808 100644 --- a/datastore/filebased_test.go +++ b/datastore/filebased_test.go @@ -2,8 +2,10 @@ package datastore import ( "fmt" + "io/fs" "io/ioutil" "os" + "path/filepath" "testing" "time" @@ -11,31 +13,58 @@ import ( "github.com/stretchr/testify/suite" actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" "www.velocidex.com/golang/velociraptor/config" - "www.velocidex.com/golang/velociraptor/constants" "www.velocidex.com/golang/velociraptor/paths" "www.velocidex.com/golang/velociraptor/utils" ) type FilebasedTestSuite struct { BaseTestSuite + dirname string } -func TestFilebasedDatabase(t *testing.T) { - dir, err := ioutil.TempDir("", "datastore_test") - assert.NoError(t, err) +func (self FilebasedTestSuite) DumpDirectory() { + filepath.Walk(self.dirname, func(path string, + info fs.FileInfo, err error) error { + if !info.IsDir() { + fmt.Printf("%v: %v\n", path, info.Size()) + } + return nil + }) +} - defer os.RemoveAll(dir) // clean up +func (self FilebasedTestSuite) TestSetGetSubjectWithEscaping() { + self.BaseTestSuite.TestSetGetSubjectWithEscaping() + self.DumpDirectory() +} - config_obj := config.GetDefaultConfig() - config_obj.Datastore.FilestoreDirectory = dir - config_obj.Datastore.Location = dir +func (self FilebasedTestSuite) TestSetGetJSON() { + self.BaseTestSuite.TestSetGetJSON() + self.DumpDirectory() +} + +func (self *FilebasedTestSuite) SetupTest() { + var err error + self.dirname, err = ioutil.TempDir("", "datastore_test") + assert.NoError(self.T(), err) + + self.config_obj = config.GetDefaultConfig() + self.config_obj.Datastore.FilestoreDirectory = self.dirname + self.config_obj.Datastore.Location = self.dirname + self.BaseTestSuite.config_obj = self.config_obj +} - suite.Run(t, &FilebasedTestSuite{BaseTestSuite{ - datastore: &FileBaseDataStore{ - clock: utils.MockClock{MockNow: time.Unix(100, 0)}, +func (self FilebasedTestSuite) TearDownTest() { + os.RemoveAll(self.dirname) // clean up +} + +func TestFilebasedDatabase(t *testing.T) { + suite.Run(t, &FilebasedTestSuite{ + BaseTestSuite: BaseTestSuite{ + datastore: &FileBaseDataStore{ + clock: utils.MockClock{MockNow: time.Unix(100, 0)}, + }, }, - config_obj: config_obj, - }}) + }) } func benchmarkSearchClientCount(b *testing.B, count int, sort_direction SortingSense) { @@ -77,7 +106,7 @@ func benchmarkSearchClientCount(b *testing.B, count int, sort_direction SortingS "label:Host" + client_id, } - err = db.SetIndex(config_obj, constants.CLIENT_INDEX_URN, + err = db.SetIndex(config_obj, paths.CLIENT_INDEX_URN, client_id, keywords) if err != nil { fmt.Printf("Failed %v\n", err) @@ -103,7 +132,7 @@ func benchmarkSearchClientCount(b *testing.B, count int, sort_direction SortingS for i := 0; i < b.N; i++ { // Only retrieve the first 10 clients for the first page. hits := db.SearchClients( - config_obj, constants.CLIENT_INDEX_URN, + config_obj, paths.CLIENT_INDEX_URN, bm.query, "", 0, 10, sort_direction) if len(hits) != bm.expected { fmt.Printf("Got %v hits (%v) expected %v\n", diff --git a/datastore/memory.go b/datastore/memory.go index c2641f57362..8234a5fd183 100644 --- a/datastore/memory.go +++ b/datastore/memory.go @@ -1,9 +1,14 @@ package datastore +/* + An in-memory data store for tests. +*/ + import ( "fmt" "os" "path" + "runtime" "sort" "strings" "sync" @@ -14,6 +19,8 @@ import ( "google.golang.org/protobuf/proto" config_proto "www.velocidex.com/golang/velociraptor/config/proto" crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/json" "www.velocidex.com/golang/velociraptor/utils" ) @@ -27,6 +34,7 @@ type TestDataStore struct { idx uint64 Subjects map[string]proto.Message + Components map[string][]string ClientTasks map[string][]*crypto_proto.VeloMessage clock utils.Clock @@ -35,6 +43,7 @@ type TestDataStore struct { func NewTestDataStore() *TestDataStore { return &TestDataStore{ Subjects: make(map[string]proto.Message), + Components: make(map[string][]string), ClientTasks: make(map[string][]*crypto_proto.VeloMessage), } } @@ -52,6 +61,7 @@ func (self *TestDataStore) Clear() { defer self.mu.Unlock() self.Subjects = make(map[string]proto.Message) + self.Components = make(map[string][]string) self.ClientTasks = make(map[string][]*crypto_proto.VeloMessage) } @@ -79,35 +89,36 @@ func (self *TestDataStore) GetClientTasks(config_obj *config_proto.Config, return result, nil } +// If child_components are a subpath of parent_components (i.e. are +// parent_components is an exact prefix of child_components) +func isSubPath(parent_components []string, child_components []string) bool { + if len(parent_components) > len(child_components) { + return false + } + + for i := 0; i < len(parent_components); i++ { + if parent_components[i] != child_components[i] { + return false + } + } + return true +} + func (self *TestDataStore) Walk( config_obj *config_proto.Config, - root string, walkFn WalkFunc) error { + root api.DSPathSpec, walkFn WalkFunc) error { self.mu.Lock() defer self.mu.Unlock() - root_components := utils.SplitComponents(root) - - is_subpath := func(components []string) bool { - if len(root_components) > len(components) { - return false - } - - for i := 0; i < len(root_components); i++ { - if root_components[i] != components[i] { - return false - } - } - return true - } - + root_components := root.Components() for k := range self.Subjects { - components := utils.SplitComponents(k) - if !is_subpath(components) { + components := self.Components[k] + if !isSubPath(root_components, components) { continue } - walkFn(k) + walkFn(path_specs.NewSafeDatastorePath(components...)) } return nil @@ -157,17 +168,29 @@ func (self *TestDataStore) UnQueueMessageForClient( return nil } +func (self *TestDataStore) Trace(name, filename string) { + return + fmt.Printf("Trace TestDataStore: %v: %v\n", name, filename) +} + func (self *TestDataStore) GetSubject( config_obj *config_proto.Config, - urn string, + urn api.DSPathSpec, message proto.Message) error { self.mu.Lock() defer self.mu.Unlock() - result, pres := self.Subjects[urn] + path := pathSpecToPath(urn, config_obj) + self.Trace("GetSubject", path) + result, pres := self.Subjects[path] if !pres { - return errors.WithMessage(os.ErrNotExist, - fmt.Sprintf("While openning %v: not found", urn)) + fallback_path := pathSpecToPath( + urn.SetType(api.PATH_TYPE_DATASTORE_PROTO), config_obj) + result, pres = self.Subjects[fallback_path] + if !pres { + return errors.WithMessage(os.ErrNotExist, + fmt.Sprintf("While openning %v: not found", urn)) + } } proto.Merge(message, result) return nil @@ -175,23 +198,30 @@ func (self *TestDataStore) GetSubject( func (self *TestDataStore) SetSubject( config_obj *config_proto.Config, - urn string, + urn api.DSPathSpec, message proto.Message) error { self.mu.Lock() defer self.mu.Unlock() - self.Subjects[urn] = message + filename := pathSpecToPath(urn, config_obj) + self.Trace("SetSubject", filename) + + self.Subjects[filename] = message + self.Components[filename] = urn.Components() return nil } func (self *TestDataStore) DeleteSubject( config_obj *config_proto.Config, - urn string) error { + urn api.DSPathSpec) error { self.mu.Lock() defer self.mu.Unlock() - delete(self.Subjects, urn) + filename := pathSpecToPath(urn, config_obj) + self.Trace("DeleteSubject", filename) + delete(self.Subjects, filename) + delete(self.Components, filename) return nil } @@ -199,92 +229,103 @@ func (self *TestDataStore) DeleteSubject( // Lists all the children of a URN. func (self *TestDataStore) ListChildren( config_obj *config_proto.Config, - urn string, - offset uint64, length uint64) ([]string, error) { + urn api.DSPathSpec, + offset uint64, length uint64) ( + []api.DSPathSpec, error) { self.mu.Lock() defer self.mu.Unlock() - result := []string{} - names, err := self.listChildren(config_obj, urn, offset, length) - if err != nil { - return nil, err + self.Trace("ListChildren", pathDirSpecToPath(urn, config_obj)) + + seen := make(map[string]bool) + root_components := urn.Components() + names := []string{} + for _, components := range self.Components { + // We only want direct children + if len(components) != len(root_components)+1 { + continue + } + + if !isSubPath(root_components, components) { + continue + } + + name := components[len(components)-1] + _, pres := seen[name] + if !pres { + names = append(names, name) + seen[name] = true + } } + + sort.Strings(names) + + result := make([]api.DSPathSpec, 0, len(names)) for _, name := range names { - result = append(result, urn+"/"+name) + result = append(result, urn.AddChild(name)) } end := offset + length if end > uint64(len(result)) { end = uint64(len(result)) } - sort.Strings(result) - return result[offset:end], nil } -func (self *TestDataStore) listChildren( - config_obj *config_proto.Config, - urn string, - offset uint64, length uint64) ([]string, error) { - - result := []string{} - - for k := range self.Subjects { - if strings.HasPrefix(k, urn) { - k = strings.TrimLeft(strings.TrimPrefix(k, urn), "/") - components := strings.Split(k, "/") - if len(components) > 0 && - !utils.InString(result, components[0]) { - result = append(result, components[0]) - } - } - } - - return result, nil -} - // Update the posting list index. Searching for any of the // keywords will return the entity urn. func (self *TestDataStore) SetIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error { self.mu.Lock() defer self.mu.Unlock() + entity = utils.SanitizeString(entity) + for _, keyword := range keywords { - subject := path.Join(index_urn, strings.ToLower(keyword), entity) + keyword = utils.SanitizeString(strings.ToLower(keyword)) + components := index_urn.AddChild(keyword, entity) + subject := pathSpecToPath(components, config_obj) self.Subjects[subject] = &empty.Empty{} + self.Components[subject] = components.Components() } return nil } func (self *TestDataStore) UnsetIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error { self.mu.Lock() defer self.mu.Unlock() + entity = utils.SanitizeString(entity) for _, keyword := range keywords { - subject := path.Join(index_urn, strings.ToLower(keyword), entity) + keyword = utils.SanitizeString(strings.ToLower(keyword)) + subject := pathSpecToPath( + index_urn.AddChild(keyword, entity), config_obj) delete(self.Subjects, subject) + delete(self.Components, subject) } return nil } func (self *TestDataStore) CheckIndex( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, entity string, keywords []string) error { self.mu.Lock() defer self.mu.Unlock() + entity = utils.SanitizeString(entity) for _, keyword := range keywords { - subject := path.Join(index_urn, strings.ToLower(keyword), entity) + keyword = utils.SanitizeString(strings.ToLower(keyword)) + subject := pathSpecToPath( + index_urn.AddChild(keyword, entity), config_obj) _, pres := self.Subjects[subject] if pres { return nil @@ -293,35 +334,51 @@ func (self *TestDataStore) CheckIndex( return errors.New("Client does not have label") } +// List all direct children +func (self *TestDataStore) listChildren(urn api.DSPathSpec) []string { + seen := make(map[string]bool) + result := []string{} + + root_components := urn.Components() + for _, components := range self.Components { + if !isSubPath(root_components, components) { + continue + } + + if len(root_components) < len(components) { + direct_child := components[len(root_components)] + _, pres := seen[direct_child] + if !pres { + result = append(result, direct_child) + seen[direct_child] = true + } + } + } + return result +} + func (self *TestDataStore) SearchClients( config_obj *config_proto.Config, - index_urn string, + index_urn api.DSPathSpec, query string, query_type string, offset uint64, limit uint64, sort_direction SortingSense) []string { seen := make(map[string]bool) result := []string{} - self.mu.Lock() - defer self.mu.Unlock() - query = strings.ToLower(query) if query == "." || query == "" { query = "all" } add_func := func(key string) { - children, err := self.listChildren(config_obj, - path.Join(index_urn, key), 0, 1000) - if err != nil { - return - } - - for _, child_urn := range children { - name := path.Base(child_urn) - seen[name] = true + children := self.listChildren( + index_urn.AddChild(utils.SanitizeString(key))) + for _, child_name := range children { + name := utils.UnsanitizeComponent(child_name) + _, pres := seen[name] + if !pres { + seen[name] = true - if uint64(len(seen)) > offset+limit { - break } } } @@ -330,12 +387,8 @@ func (self *TestDataStore) SearchClients( if strings.ContainsAny(query, "[]*?") { // We could make it smarter in future but this is // quick enough for now. - sets, err := self.listChildren(config_obj, index_urn, 0, 1000) - if err != nil { - return result - } - for _, set := range sets { - name := path.Base(set) + for _, name := range self.listChildren(index_urn) { + name = utils.UnsanitizeComponent(name) matched, err := path.Match(query, name) if err != nil { // Can only happen if pattern is invalid. @@ -391,3 +444,31 @@ func (self *TestDataStore) Close() { gTestDatastore = NewTestDataStore() } + +func pathSpecToPath(p api.DSPathSpec, + config_obj *config_proto.Config) string { + result := p.AsDatastoreFilename(config_obj) + + // Sanitize it on windows to convert back to a common format + // for comparisons. + if runtime.GOOS == "windows" { + return path.Clean(strings.Replace(strings.TrimPrefix( + result, path_specs.WINDOWS_LFN_PREFIX), "\\", "/", -1)) + } + + return result +} + +func pathDirSpecToPath(p api.DSPathSpec, + config_obj *config_proto.Config) string { + result := p.AsDatastoreDirectory(config_obj) + + // Sanitize it on windows to convert back to a common format + // for comparisons. + if runtime.GOOS == "windows" { + return path.Clean(strings.Replace(strings.TrimPrefix( + result, path_specs.WINDOWS_LFN_PREFIX), "\\", "/", -1)) + } + + return result +} diff --git a/datastore/paths.go b/datastore/paths.go new file mode 100644 index 00000000000..1ea451e03b2 --- /dev/null +++ b/datastore/paths.go @@ -0,0 +1 @@ +package datastore diff --git a/file_store/api/accessor.go b/file_store/accessors/accessor.go similarity index 62% rename from file_store/api/accessor.go rename to file_store/accessors/accessor.go index 1814b20717b..1ff0ea362fe 100644 --- a/file_store/api/accessor.go +++ b/file_store/accessors/accessor.go @@ -1,4 +1,4 @@ -package api +package accessors // This implements a filesystem accessor which can be used to access // the generic filestore. This allows us to run globs on the file @@ -8,11 +8,13 @@ package api import ( "os" "path" - "path/filepath" "regexp" "time" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/json" + "www.velocidex.com/golang/velociraptor/utils" "github.com/Velocidex/ordereddict" config_proto "www.velocidex.com/golang/velociraptor/config/proto" @@ -21,31 +23,47 @@ import ( ) type FileStoreFileSystemAccessor struct { - file_store FileStore + file_store api.FileStore + config_obj *config_proto.Config } func NewFileStoreFileSystemAccessor( - config_obj *config_proto.Config, fs FileStore) *FileStoreFileSystemAccessor { - return &FileStoreFileSystemAccessor{fs} + config_obj *config_proto.Config, fs api.FileStore) *FileStoreFileSystemAccessor { + return &FileStoreFileSystemAccessor{ + file_store: fs, + config_obj: config_obj, + } } func (self FileStoreFileSystemAccessor) New( scope vfilter.Scope) glob.FileSystemAccessor { - return &FileStoreFileSystemAccessor{self.file_store} + return &FileStoreFileSystemAccessor{ + file_store: self.file_store, + config_obj: self.config_obj, + } } func (self FileStoreFileSystemAccessor) Lstat( filename string) (glob.FileInfo, error) { - lstat, err := self.file_store.StatFile(filename) + + fullpath := path_specs.NewUnsafeFilestorePath( + utils.SplitComponents(filename)...) + lstat, err := self.file_store.StatFile(fullpath) if err != nil { return nil, err } - return &FileStoreFileInfo{lstat, filename, nil}, nil + return &FileStoreFileInfo{ + FileInfo: lstat, + config_obj: self.config_obj, + fullpath: fullpath, + }, nil } func (self FileStoreFileSystemAccessor) ReadDir(path string) ([]glob.FileInfo, error) { - files, err := self.file_store.ListDirectory(path) + fullpath := path_specs.NewUnsafeFilestorePath( + utils.SplitComponents(path)...) + files, err := self.file_store.ListDirectory(fullpath) if err != nil { return nil, err } @@ -53,14 +71,20 @@ func (self FileStoreFileSystemAccessor) ReadDir(path string) ([]glob.FileInfo, e var result []glob.FileInfo for _, f := range files { result = append(result, - &FileStoreFileInfo{f, filepath.Join(path, f.Name()), nil}) + &FileStoreFileInfo{ + FileInfo: f, + fullpath: fullpath, + config_obj: self.config_obj, + }) } return result, nil } func (self FileStoreFileSystemAccessor) Open(path string) (glob.ReadSeekCloser, error) { - file, err := self.file_store.ReadFile(path) + components := path_specs.NewSafeFilestorePath( + utils.SplitComponents(path)...) + file, err := self.file_store.ReadFile(components) if err != nil { return nil, err } @@ -82,14 +106,26 @@ func (self *FileStoreFileSystemAccessor) GetRoot(path string) (string, string, e return "/", path, nil } +func NewFileStoreFileInfo( + config_obj *config_proto.Config, + fullpath api.FSPathSpec, + info os.FileInfo) *FileStoreFileInfo { + return &FileStoreFileInfo{ + config_obj: config_obj, + FileInfo: info, + fullpath: fullpath, + } +} + type FileStoreFileInfo struct { os.FileInfo - FullPath_ string - Data_ interface{} + fullpath api.FSPathSpec + config_obj *config_proto.Config + Data_ interface{} } func (self FileStoreFileInfo) Name() string { - return self.FileInfo.Name() + return self.fullpath.Base() } func (self *FileStoreFileInfo) Data() interface{} { @@ -101,7 +137,11 @@ func (self *FileStoreFileInfo) Data() interface{} { } func (self *FileStoreFileInfo) FullPath() string { - return self.FullPath_ + return self.fullpath.AsClientPath() +} + +func (self *FileStoreFileInfo) PathSpec() api.FSPathSpec { + return self.fullpath } func (self *FileStoreFileInfo) Btime() time.Time { @@ -125,7 +165,8 @@ func (self *FileStoreFileInfo) IsLink() bool { } func (self *FileStoreFileInfo) GetLink() (string, error) { - target, err := os.Readlink(self.FullPath_) + filename := self.fullpath.AsFilestoreFilename(self.config_obj) + target, err := os.Readlink(filename) if err != nil { return "", err } @@ -161,3 +202,12 @@ func (self *FileStoreFileInfo) MarshalJSON() ([]byte, error) { func (self *FileStoreFileInfo) UnmarshalJSON(data []byte) error { return nil } + +type FileReaderAdapter struct { + api.FileReader +} + +func (self *FileReaderAdapter) Stat() (os.FileInfo, error) { + stat, err := self.FileReader.Stat() + return stat, err +} diff --git a/file_store/api/fs.go b/file_store/accessors/fs.go similarity index 57% rename from file_store/api/fs.go rename to file_store/accessors/fs.go index cb8ae2da264..4c2043f0db1 100644 --- a/file_store/api/fs.go +++ b/file_store/accessors/fs.go @@ -1,4 +1,4 @@ -package api +package accessors import ( "net/http" @@ -6,13 +6,16 @@ import ( "strings" config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" + "www.velocidex.com/golang/velociraptor/utils" ) type HTTPFileAdapter struct { - FileReader - file_store FileStore + api.FileReader + file_store api.FileStore - filename string + filename api.FSPathSpec } func (self *HTTPFileAdapter) Stat() (os.FileInfo, error) { @@ -21,13 +24,22 @@ func (self *HTTPFileAdapter) Stat() (os.FileInfo, error) { } func (self HTTPFileAdapter) Readdir(count int) ([]os.FileInfo, error) { - return self.file_store.ListDirectory(self.filename) + children, err := self.file_store.ListDirectory(self.filename) + if err != nil { + return nil, err + } + result := make([]os.FileInfo, 0, len(children)) + for _, i := range children { + result = append(result, i) + } + + return result, nil } // Implementation of http.FileSystem type FileSystem struct { config_obj *config_proto.Config - file_store FileStore + file_store api.FileStore // The required prefix of the filesystem. prefix string @@ -38,7 +50,9 @@ func (self FileSystem) Open(path string) (http.File, error) { return nil, os.ErrNotExist } - fd, err := self.file_store.ReadFile(path) + components := path_specs.NewSafeFilestorePath( + utils.SplitComponents(path)...) + fd, err := self.file_store.ReadFile(components) if err != nil { return nil, os.ErrNotExist } @@ -46,13 +60,13 @@ func (self FileSystem) Open(path string) (http.File, error) { return &HTTPFileAdapter{ FileReader: fd, file_store: self.file_store, - filename: path, + filename: components, }, nil } func NewFileSystem( config_obj *config_proto.Config, - file_store FileStore, + file_store api.FileStore, prefix string) *FileSystem { return &FileSystem{ config_obj: config_obj, diff --git a/file_store/api/adapter.go b/file_store/api/adapter.go index 6115d406bf2..008ff71c7aa 100644 --- a/file_store/api/adapter.go +++ b/file_store/api/adapter.go @@ -6,18 +6,19 @@ import ( "github.com/Velocidex/ordereddict" "github.com/pkg/errors" - "www.velocidex.com/golang/velociraptor/glob" + "www.velocidex.com/golang/velociraptor/utils" ) // Implement the glob.FileInfo type FileInfoAdapter struct { os.FileInfo - full_path string + full_path FSPathSpec _data interface{} } -func NewFileInfoAdapter(fd os.FileInfo, full_path string, data interface{}) *FileInfoAdapter { +func NewFileInfoAdapter(fd os.FileInfo, + full_path FSPathSpec, data interface{}) *FileInfoAdapter { return &FileInfoAdapter{ FileInfo: fd, full_path: full_path, @@ -25,6 +26,10 @@ func NewFileInfoAdapter(fd os.FileInfo, full_path string, data interface{}) *Fil } } +func (self FileInfoAdapter) PathSpec() FSPathSpec { + return self.full_path +} + func (self FileInfoAdapter) Data() interface{} { if self._data == nil { return ordereddict.NewDict() @@ -34,7 +39,7 @@ func (self FileInfoAdapter) Data() interface{} { } func (self FileInfoAdapter) FullPath() string { - return self.full_path + return utils.JoinComponents(self.full_path.Components(), "/") } func (self FileInfoAdapter) Btime() time.Time { @@ -61,25 +66,22 @@ func (self FileInfoAdapter) GetLink() (string, error) { return "", errors.New("Not implemented") } +// A Wrapper around a regular file to present the glob.FileInfo +// interface type FileAdapter struct { *os.File - FullPath string + PathSpec_ FSPathSpec +} + +func (self *FileAdapter) PathSpec() FSPathSpec { + return self.PathSpec_ } -func (self *FileAdapter) Stat() (glob.FileInfo, error) { +func (self *FileAdapter) Stat() (FileInfo, error) { stat, err := self.File.Stat() if err != nil { return nil, err } - return NewFileInfoAdapter(stat, self.FullPath, nil), nil -} - -type FileReaderAdapter struct { - FileReader -} - -func (self *FileReaderAdapter) Stat() (os.FileInfo, error) { - stat, err := self.FileReader.Stat() - return stat, err + return NewFileInfoAdapter(stat, self.PathSpec_, nil), nil } diff --git a/file_store/api/extensions.go b/file_store/api/extensions.go new file mode 100644 index 00000000000..a826e416343 --- /dev/null +++ b/file_store/api/extensions.go @@ -0,0 +1,104 @@ +package api + +import ( + "strings" +) + +func GetExtensionForDatastore(path_spec DSPathSpec, t PathType) string { + switch t { + case PATH_TYPE_DATASTORE_PROTO: + return ".db" + + case PATH_TYPE_DATASTORE_JSON: + return ".json.db" + + } + return ".db" +} + +func GetExtensionForFilestore(path_spec FSPathSpec, t PathType) string { + switch t { + case PATH_TYPE_DATASTORE_PROTO, PATH_TYPE_DATASTORE_JSON: + panic("datastore path used for filestore for " + + path_spec.AsClientPath()) + + case PATH_TYPE_FILESTORE_JSON: + return ".json" + + case PATH_TYPE_FILESTORE_JSON_INDEX: + return ".json.index" + + case PATH_TYPE_FILESTORE_JSON_TIME_INDEX: + return ".json.tidx" + + case PATH_TYPE_FILESTORE_SPARSE_IDX: + return ".idx" + + case PATH_TYPE_FILESTORE_DOWNLOAD_ZIP: + return ".zip" + + case PATH_TYPE_FILESTORE_DOWNLOAD_REPORT: + return ".html" + + case PATH_TYPE_FILESTORE_TMP: + return ".tmp" + + case PATH_TYPE_FILESTORE_LOCK: + return ".lock" + + case PATH_TYPE_FILESTORE_CSV: + return ".csv" + + case PATH_TYPE_FILESTORE_YAML: + return ".yaml" + + case PATH_TYPE_FILESTORE_ANY: + return "" + } + + return "" +} + +func GetFileStorePathTypeFromExtension(name string) (PathType, string) { + if strings.HasSuffix(name, ".json") { + return PATH_TYPE_FILESTORE_JSON, name[:len(name)-5] + } + + if strings.HasSuffix(name, ".json.index") { + return PATH_TYPE_FILESTORE_JSON_INDEX, name[:len(name)-11] + } + + if strings.HasSuffix(name, ".json.tidx") { + return PATH_TYPE_FILESTORE_JSON_TIME_INDEX, name[:len(name)-10] + } + + if strings.HasSuffix(name, ".idx") { + return PATH_TYPE_FILESTORE_SPARSE_IDX, name[:len(name)-4] + } + + if strings.HasSuffix(name, ".zip") { + return PATH_TYPE_FILESTORE_DOWNLOAD_ZIP, name[:len(name)-4] + } + + if strings.HasSuffix(name, ".html") { + return PATH_TYPE_FILESTORE_DOWNLOAD_REPORT, name[:len(name)-5] + } + + if strings.HasSuffix(name, ".tmp") { + return PATH_TYPE_FILESTORE_TMP, name[:len(name)-4] + } + + if strings.HasSuffix(name, ".lock") { + return PATH_TYPE_FILESTORE_LOCK, name[:len(name)-5] + } + + if strings.HasSuffix(name, ".csv") { + return PATH_TYPE_FILESTORE_CSV, name[:len(name)-4] + } + + if strings.HasSuffix(name, ".yaml") { + return PATH_TYPE_FILESTORE_YAML, name[:len(name)-5] + } + + return PATH_TYPE_FILESTORE_ANY, name +} diff --git a/file_store/api/file_store.go b/file_store/api/file_store.go index 29c1591885f..ed35b2cfc21 100644 --- a/file_store/api/file_store.go +++ b/file_store/api/file_store.go @@ -19,15 +19,12 @@ package api import ( "os" - "path/filepath" - - "www.velocidex.com/golang/velociraptor/glob" ) type FileReader interface { Read(buff []byte) (int, error) Seek(offset int64, whence int) (int64, error) - Stat() (glob.FileInfo, error) + Stat() (FileInfo, error) Close() error } @@ -42,12 +39,18 @@ type FileWriter interface { Close() error } +type FileInfo interface { + os.FileInfo + PathSpec() FSPathSpec +} + +type WalkFunc func(urn FSPathSpec, info os.FileInfo) error type FileStore interface { - ReadFile(filename string) (FileReader, error) - WriteFile(filename string) (FileWriter, error) - StatFile(filename string) (os.FileInfo, error) - ListDirectory(dirname string) ([]os.FileInfo, error) - Walk(root string, cb filepath.WalkFunc) error - Delete(filename string) error - Move(src, dest string) error + ReadFile(filename FSPathSpec) (FileReader, error) + WriteFile(filename FSPathSpec) (FileWriter, error) + StatFile(filename FSPathSpec) (FileInfo, error) + ListDirectory(dirname FSPathSpec) ([]FileInfo, error) + Walk(root FSPathSpec, cb WalkFunc) error + Delete(filename FSPathSpec) error + Move(src, dest FSPathSpec) error } diff --git a/file_store/api/paths.go b/file_store/api/paths.go new file mode 100644 index 00000000000..6efbd6fa5b6 --- /dev/null +++ b/file_store/api/paths.go @@ -0,0 +1,146 @@ +package api + +import ( + config_proto "www.velocidex.com/golang/velociraptor/config/proto" +) + +/* + +# How paths are handled in Velociraptor. + +Velociraptor treats paths as a list of components. Each component is a +string which may contain arbitrary bytes - including path separators. + +Ultimately these paths need to be encoded into a filesystem backend +which has many rules about the types of characters allowed on them. We +therefore need to apply conversions to make the general path fit in +the fileystem backend restrictions - this process is called +Sanitization. + +For example consider a path like: ["a", "b/c"] + +The path consists of two components, one of which happens to have a +path separator. Therefore in order to store it on the filesystem we +must sanitize the components and come up with a filesystem path like +this: "/a/b%2Ec/" + +Velociraptor paths can come from many different sources but all +internal representations consist of a list of components. For example: + +Client path -> paths.UnsafeDatastorePathFromClientPath() -> UnsafeDatastorePath() +path managers -> SafeDatastorePath() + +## SafeDatastorePath vs. UnsafeDatastorePath + +When encoding to the filesystem, a Velociraptor path needs to be +sanitized. There are some cases where we know this sanitization is not +needed. Namely when the path is created by a path manager and does not +contain user input. In this case we can take a shortcut - we do not +need to sanitize the data when we write the path in the backing +filesystem (because we have full control over the path components). + +For example, consider the path to a client's datastore record: +["clients", client_id] + +There is no need to escape anything especially here, since we know all +the components to be safe. + +Consider this path from the client: +["clients", client_id, "vfs", "ntfs", "\\\\.\\c:\\", "Windows"] + +This path might need to be escaped since it comes from the client +(specifically the device name). Therefore we construct an +UnsafeDatastorePath. + +We can convert between an UnsafeDatastorePath to a SafeDatastorePath +by simply sanitizing all components. + +This design strikes a balance between: + +1. Avoids the need for any other code to worry about filestore + encoding since encoding happens only at the file store - + everything else just passes the raw component slice around. + +2. Avoids the need to encode/decode paths that are fixed and safe + such as paths created for internal use with already known safe + names. + +Ultimately the path managers determine which API is most appropriate +by either offering a safe or unsafe path spec +*/ + +type PathType int + +const ( + // By default prefer to store datastore items as JSON but some + // items may still be protobuf when performance is needed. + PATH_TYPE_DATASTORE_JSON PathType = iota + PATH_TYPE_DATASTORE_PROTO + + PATH_TYPE_FILESTORE_JSON + PATH_TYPE_FILESTORE_JSON_INDEX + PATH_TYPE_FILESTORE_JSON_TIME_INDEX + + // Used to write sparse indexes + PATH_TYPE_FILESTORE_SPARSE_IDX + + // Used to write zip files in the download folder. + PATH_TYPE_FILESTORE_DOWNLOAD_ZIP + PATH_TYPE_FILESTORE_DOWNLOAD_REPORT + + // TMP files + PATH_TYPE_FILESTORE_TMP + PATH_TYPE_FILESTORE_LOCK + PATH_TYPE_FILESTORE_CSV + + // Used for artifacts + PATH_TYPE_FILESTORE_YAML + + // Arbitrary extensions. + PATH_TYPE_FILESTORE_ANY +) + +type _PathSpec interface { + // A path suitable to be exchanged with the client. + AsClientPath() string + + Components() []string + Base() string + Type() PathType +} + +type DSPathSpec interface { + _PathSpec + AsDatastoreDirectory(config_obj *config_proto.Config) string + AsDatastoreFilename(config_obj *config_proto.Config) string + + Dir() DSPathSpec + + SetType(t PathType) DSPathSpec + + // Adds a child maintaining safety (i.e. for a safe path keeps + // the path safe, and for unsafe paths keep them as unsafe). + AddChild(child ...string) DSPathSpec + + // Adds children but makes sure that the result is unsafe. + AddUnsafeChild(child ...string) DSPathSpec + + AsFilestorePath() FSPathSpec +} + +type FSPathSpec interface { + _PathSpec + AsFilestoreFilename(config_obj *config_proto.Config) string + AsFilestoreDirectory(config_obj *config_proto.Config) string + + Dir() FSPathSpec + + SetType(t PathType) FSPathSpec + + // Adds a child maintaining safety (i.e. for a safe path keeps + // the path safe, and for unsafe paths keep them as unsafe). + AddChild(child ...string) FSPathSpec + + // Adds children but makes sure that the result is unsafe. + AddUnsafeChild(child ...string) FSPathSpec +} diff --git a/file_store/api/queues.go b/file_store/api/queues.go index 09bf90f422f..5bbd9446606 100644 --- a/file_store/api/queues.go +++ b/file_store/api/queues.go @@ -16,7 +16,7 @@ type QueueManager interface { } type ResultSetFileProperties struct { - Path string + Path FSPathSpec StartTime, EndTime time.Time Size int64 } @@ -24,7 +24,7 @@ type ResultSetFileProperties struct { // Path manager tells the filestore where to store things. type PathManager interface { // Gets a log path for writing new rows on. - GetPathForWriting() (string, error) + GetPathForWriting() (FSPathSpec, error) // The name of the queue we will use to watch for any rows // inserted into this result set. diff --git a/file_store/api/uploader.go b/file_store/api/uploader.go index a03eb0f08b1..ad63ba3d4a2 100644 --- a/file_store/api/uploader.go +++ b/file_store/api/uploader.go @@ -6,10 +6,10 @@ import ( "crypto/sha256" "encoding/hex" "io" - "path" "time" config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/utils" "www.velocidex.com/golang/vfilter" ) @@ -39,7 +39,7 @@ type Uploader interface { // An uploader into the filestore. type FileStoreUploader struct { file_store FileStore - root_path string + root_path FSPathSpec } func (self *FileStoreUploader) Upload( @@ -57,8 +57,7 @@ func (self *FileStoreUploader) Upload( store_as_name = filename } - output_path := path.Join(self.root_path, store_as_name) - + output_path := self.root_path.AddChild(store_as_name) out_fd, err := self.file_store.WriteFile(output_path) if err != nil { scope.Log("Unable to open file %s: %v", store_as_name, err) @@ -104,7 +103,7 @@ loop: scope.Log("Uploaded %v (%v bytes)", output_path, offset) return &UploadResponse{ - Path: output_path, + Path: utils.JoinComponents(output_path.Components(), "/"), Size: uint64(offset), Sha256: hex.EncodeToString(sha_sum.Sum(nil)), Md5: hex.EncodeToString(md5_sum.Sum(nil)), @@ -114,6 +113,6 @@ loop: func NewFileStoreUploader( config_obj *config_proto.Config, fs FileStore, - root_path string) *FileStoreUploader { + root_path FSPathSpec) *FileStoreUploader { return &FileStoreUploader{fs, root_path} } diff --git a/file_store/directory/csv.go b/file_store/directory/csv.go index c2a7d356731..3840bc9a715 100644 --- a/file_store/directory/csv.go +++ b/file_store/directory/csv.go @@ -34,7 +34,7 @@ func row_to_dict(row_data []interface{}, headers []string) (*ordereddict.Dict, i func ReadRowsCSV( ctx context.Context, file_store api.FileStore, - log_path string, start_time, end_time int64) ( + log_path api.FSPathSpec, start_time, end_time int64) ( <-chan *ordereddict.Dict, error) { fd, err := file_store.ReadFile(log_path) diff --git a/file_store/directory/directory.go b/file_store/directory/directory.go index 36e96dd3917..c2a7c994231 100644 --- a/file_store/directory/directory.go +++ b/file_store/directory/directory.go @@ -30,16 +30,14 @@ package directory import ( "os" - "path" "path/filepath" - "runtime" "strings" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" config_proto "www.velocidex.com/golang/velociraptor/config/proto" - "www.velocidex.com/golang/velociraptor/datastore" + "www.velocidex.com/golang/velociraptor/file_store/accessors" "www.velocidex.com/golang/velociraptor/file_store/api" logging "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/utils" @@ -96,56 +94,77 @@ func NewDirectoryFileStore(config_obj *config_proto.Config) *DirectoryFileStore return &DirectoryFileStore{config_obj} } -func (self *DirectoryFileStore) Move(src string, dest string) error { - src_path := self.FilenameToFileStorePath(src) - dest_path := self.FilenameToFileStorePath(dest) +func (self *DirectoryFileStore) Move(src, dest api.FSPathSpec) error { + src_path := src.AsFilestoreFilename(self.config_obj) + dest_path := dest.AsFilestoreFilename(self.config_obj) return os.Rename(src_path, dest_path) } -func (self *DirectoryFileStore) ListDirectory(dirname string) ( - []os.FileInfo, error) { +func (self *DirectoryFileStore) ListDirectory(dirname api.FSPathSpec) ( + []api.FileInfo, error) { listCounter.Inc() - file_path := self.FilenameToFileStorePath(dirname) + file_path := dirname.AsFilestoreDirectory(self.config_obj) files, err := utils.ReadDir(file_path) if err != nil { return nil, err } - var result []os.FileInfo + var result []api.FileInfo for _, fileinfo := range files { - result = append(result, &api.FileStoreFileInfo{ - FileInfo: fileinfo, - FullPath_: utils.PathJoin(dirname, fileinfo.Name(), "/")}) + // Each file from the filesystem will be potentially + // encoded. + name := fileinfo.Name() + + // Eliminate the data store files + if strings.HasSuffix(name, ".db") { + continue + } + + name_type, name := api.GetFileStorePathTypeFromExtension(name) + result = append(result, accessors.NewFileStoreFileInfo( + self.config_obj, + dirname.AddChild( + utils.UnsanitizeComponent(name)). + SetType(name_type), + fileinfo)) } return result, nil } -func (self *DirectoryFileStore) ReadFile(filename string) (api.FileReader, error) { - file_path := self.FilenameToFileStorePath(filename) +func (self *DirectoryFileStore) ReadFile( + filename api.FSPathSpec) (api.FileReader, error) { + file_path := filename.AsFilestoreFilename(self.config_obj) openCounter.Inc() file, err := os.Open(file_path) if err != nil { return nil, errors.WithStack(err) } - return &api.FileAdapter{File: file, FullPath: filename}, nil + return &api.FileAdapter{ + File: file, + PathSpec_: filename, + }, nil } -func (self *DirectoryFileStore) StatFile(filename string) (os.FileInfo, error) { - file_path := self.FilenameToFileStorePath(filename) +func (self *DirectoryFileStore) StatFile( + filename api.FSPathSpec) (api.FileInfo, error) { + file_path := filename.AsFilestoreFilename(self.config_obj) file, err := os.Stat(file_path) if err != nil { return nil, err } - return &api.FileStoreFileInfo{FileInfo: file, FullPath_: filename}, nil + return &accessors.FileStoreFileInfo{ + FileInfo: file, + }, nil } -func (self *DirectoryFileStore) WriteFile(filename string) (api.FileWriter, error) { - file_path := self.FilenameToFileStorePath(filename) +func (self *DirectoryFileStore) WriteFile( + filename api.FSPathSpec) (api.FileWriter, error) { + file_path := filename.AsFilestoreFilename(self.config_obj) err := os.MkdirAll(filepath.Dir(file_path), 0700) if err != nil { logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) @@ -165,84 +184,33 @@ func (self *DirectoryFileStore) WriteFile(filename string) (api.FileWriter, erro return &DirectoryFileWriter{file}, nil } -func (self *DirectoryFileStore) Delete(filename string) error { - file_path := self.FilenameToFileStorePath(filename) +func (self *DirectoryFileStore) Delete(filename api.FSPathSpec) error { + file_path := filename.AsFilestoreFilename(self.config_obj) return os.Remove(file_path) } -// In the below: -// Filename: is an abstract filename to be represented in the file store. -// FileStorePath: An actual path to store the file on the filesystem. -// -// On windows, the FileStorePath always includes the LFN prefix. -func (self *DirectoryFileStore) FilenameToFileStorePath(filename string) string { - components := []string{self.config_obj.Datastore.FilestoreDirectory} - for _, component := range utils.SplitComponents(filename) { - components = append(components, - string(datastore.SanitizeString(component))) - } - - // OS filenames may use / or \ as separators. On windows we - // prefix the LFN prefix to be able to access long paths but - // then we must use \ as a separator. - result := filepath.Join(components...) - - if runtime.GOOS == "windows" { - return WINDOWS_LFN_PREFIX + result - } - return result -} - -// Converts from a physical path on disk to a normalized filestore path. -func (self *DirectoryFileStore) FileStorePathToFilename(filename string) ( - string, error) { - - if runtime.GOOS == "windows" { - filename = strings.TrimPrefix(filename, WINDOWS_LFN_PREFIX) - } - filename = strings.TrimPrefix(filename, - self.config_obj.Datastore.FilestoreDirectory) - - components := []string{} - for _, component := range strings.Split( - filename, - string(os.PathSeparator)) { - components = append(components, - string(datastore.UnsanitizeComponent(component))) +func (self *DirectoryFileStore) Walk(root api.FSPathSpec, walkFn api.WalkFunc) error { + // Walking a non-existant directory just returns no results. + children, err := self.ListDirectory(root) + if err != nil { + return nil } - // Filestore filenames always use / as separator. - result := "/" + path.Join(components...) - return result, nil -} - -func (self *DirectoryFileStore) Walk(root string, walkFn filepath.WalkFunc) error { - path := self.FilenameToFileStorePath(root) - return filepath.Walk(path, - func(path string, info os.FileInfo, err error) error { - // Ignore stat errors. - if info == nil || err != nil { - return nil - } - - // Not a filestore file - its a data store path. - if strings.HasSuffix(path, ".db") || - strings.HasSuffix(path, ".db\"") { - return nil + for _, child := range children { + child_spec := root.AddChild(child.Name()) + if child.IsDir() { + err = self.Walk(child_spec, walkFn) + if err != nil { + return err } + continue + } - filename, err_1 := self.FileStorePathToFilename(path) - if err_1 != nil { - return err_1 - } + if strings.HasSuffix(child.Name(), ".db") { + continue + } - if !info.IsDir() { - return walkFn(filename, - &api.FileStoreFileInfo{ - FileInfo: info, - FullPath_: path, - }, err) - } - return nil - }) + walkFn(child_spec, child) + } + return nil } diff --git a/file_store/directory/directory_components.go b/file_store/directory/directory_components.go new file mode 100644 index 00000000000..f1ed8b118dd --- /dev/null +++ b/file_store/directory/directory_components.go @@ -0,0 +1,108 @@ +// +build deprecated + +package directory + +import ( + "os" + "path/filepath" + "runtime" + + "github.com/pkg/errors" + "www.velocidex.com/golang/velociraptor/file_store/api" + logging "www.velocidex.com/golang/velociraptor/logging" + "www.velocidex.com/golang/velociraptor/utils" +) + +func (self *DirectoryFileStore) ComponentsToFileStorePath( + components []string) string { + sanitized_components := append(make([]string, 0, len(components)), + self.config_obj.Datastore.FilestoreDirectory) + for _, component := range components { + sanitized_components = append(sanitized_components, + utils.SanitizeString(component)) + } + + // OS filenames may use / or \ as separators. On windows we + // prefix the LFN prefix to be able to access long paths but + // then we must use \ as a separator. + result := filepath.Join(sanitized_components...) + + if runtime.GOOS == "windows" { + return WINDOWS_LFN_PREFIX + result + } + return result +} + +func (self *DirectoryFileStore) ListDirectoryComponents(components []string) ( + []os.FileInfo, error) { + + listCounter.Inc() + + file_path := self.ComponentsToFileStorePath(components) + files, err := utils.ReadDir(file_path) + if err != nil { + return nil, err + } + + var result []os.FileInfo + for _, fileinfo := range files { + // Make a copy of the components for the child. + child_components := append( + make([]string, 0, len(components)+1), components...) + result = append(result, &api.FileStoreFileInfo{ + FileInfo: fileinfo, + }) + } + + return result, nil +} + +func (self *DirectoryFileStore) ReadFileComponents( + components []string) (api.FileReader, error) { + file_path := self.ComponentsToFileStorePath(components) + openCounter.Inc() + file, err := os.Open(file_path) + if err != nil { + return nil, errors.WithStack(err) + } + return &api.FileAdapter{ + File: file, + Components: components, + }, nil +} + +func (self *DirectoryFileStore) StatFileComponents( + components []string) (os.FileInfo, error) { + file_path := self.ComponentsToFileStorePath(components) + file, err := os.Stat(file_path) + if err != nil { + return nil, err + } + + return &api.FileStoreFileInfo{ + FileInfo: file, + Components: components, + }, nil +} + +func (self *DirectoryFileStore) WriteFileComponent( + components []string) (api.FileWriter, error) { + file_path := self.ComponentsToFileStorePath(components) + err := os.MkdirAll(filepath.Dir(file_path), 0700) + if err != nil { + logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) + logger.Error("Can not create dir: %v", err) + return nil, err + } + + openCounter.Inc() + file, err := os.OpenFile(file_path, os.O_RDWR|os.O_CREATE, 0700) + if err != nil { + logger := logging.GetLogger(self.config_obj, &logging.FrontendComponent) + logger.Error("Unable to open file %v: %v", file_path, err) + + return nil, errors.WithStack(err) + } + + return &DirectoryFileWriter{file}, nil +} diff --git a/file_store/directory/directory_test.go b/file_store/directory/directory_test.go index adcc55e22ee..5ccbc3e790e 100644 --- a/file_store/directory/directory_test.go +++ b/file_store/directory/directory_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "www.velocidex.com/golang/velociraptor/config" - "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/tests" ) func TestDirectoryFileStore(t *testing.T) { @@ -22,5 +22,5 @@ func TestDirectoryFileStore(t *testing.T) { config_obj.Datastore.Location = dir file_store := NewDirectoryFileStore(config_obj) - suite.Run(t, api.NewFileStoreTestSuite(config_obj, file_store)) + suite.Run(t, tests.NewFileStoreTestSuite(config_obj, file_store)) } diff --git a/file_store/directory/json.go b/file_store/directory/json.go index e5418c3153e..c3ee08f77f9 100644 --- a/file_store/directory/json.go +++ b/file_store/directory/json.go @@ -12,7 +12,7 @@ import ( func ReadRowsJSON( ctx context.Context, file_store api.FileStore, - log_path string, start_time, end_time int64) ( + log_path api.FSPathSpec, start_time, end_time int64) ( <-chan *ordereddict.Dict, error) { fd, err := file_store.ReadFile(log_path) diff --git a/file_store/directory/queue_test.go b/file_store/directory/queue_test.go index 7af4a1e6f15..8e1927f4529 100644 --- a/file_store/directory/queue_test.go +++ b/file_store/directory/queue_test.go @@ -13,10 +13,10 @@ import ( "github.com/stretchr/testify/suite" "www.velocidex.com/golang/velociraptor/config" config_proto "www.velocidex.com/golang/velociraptor/config/proto" - "www.velocidex.com/golang/velociraptor/file_store/api" "www.velocidex.com/golang/velociraptor/file_store/directory" "www.velocidex.com/golang/velociraptor/file_store/memory" "www.velocidex.com/golang/velociraptor/file_store/test_utils" + "www.velocidex.com/golang/velociraptor/file_store/tests" "www.velocidex.com/golang/velociraptor/paths/artifacts" "www.velocidex.com/golang/velociraptor/services" "www.velocidex.com/golang/velociraptor/services/journal" @@ -45,8 +45,10 @@ func TestDirectoryQueueManager(t *testing.T) { config_obj.Datastore.FilestoreDirectory = dir config_obj.Datastore.Location = dir - manager := directory.NewDirectoryQueueManager(config_obj, memory.Test_memory_file_store) - suite.Run(t, api.NewQueueManagerTestSuite(config_obj, manager, memory.Test_memory_file_store)) + file_store := memory.NewMemoryFileStore(config_obj) + manager := directory.NewDirectoryQueueManager(config_obj, file_store) + suite.Run(t, tests.NewQueueManagerTestSuite( + config_obj, manager, file_store)) } type TestSuite struct { diff --git a/file_store/directory/result_sets.go b/file_store/directory/result_sets.go index 47d0389b353..c3814b69af8 100644 --- a/file_store/directory/result_sets.go +++ b/file_store/directory/result_sets.go @@ -2,7 +2,6 @@ package directory import ( "context" - "strings" "github.com/Velocidex/ordereddict" "www.velocidex.com/golang/velociraptor/file_store/api" @@ -11,22 +10,8 @@ import ( func ReadRows( ctx context.Context, file_store api.FileStore, - file_path string, + file_path api.FSPathSpec, start_time, end_time int64) (<-chan *ordereddict.Dict, error) { - // Backwards compatibility: We dont write .csv files any more - // but we can read them if they are there. - if strings.HasSuffix(file_path, ".csv") { - return ReadRowsCSV(ctx, file_store, file_path, start_time, end_time) - } - - // If we are supposed to read a json file but we cant find it - // - maybe it is a csv file instead - look for it. - row_chan, err := ReadRowsJSON(ctx, file_store, file_path, start_time, end_time) - if err != nil && strings.HasSuffix(file_path, ".json") { - file_path = strings.TrimSuffix(file_path, ".json") + ".csv" - return ReadRowsCSV(ctx, file_store, file_path, start_time, end_time) - } - - return row_chan, err + return ReadRowsJSON(ctx, file_store, file_path, start_time, end_time) } diff --git a/file_store/file_store.go b/file_store/file_store.go index aa3bbeae507..559591b1ce3 100644 --- a/file_store/file_store.go +++ b/file_store/file_store.go @@ -22,6 +22,7 @@ import ( "fmt" config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store/accessors" "www.velocidex.com/golang/velociraptor/file_store/api" "www.velocidex.com/golang/velociraptor/file_store/directory" "www.velocidex.com/golang/velociraptor/file_store/memory" @@ -37,7 +38,7 @@ func GetFileStore(config_obj *config_proto.Config) api.FileStore { switch config_obj.Datastore.Implementation { case "Test": - return memory.Test_memory_file_store + return memory.NewMemoryFileStore(config_obj) case "FileBaseDataStore": return directory.NewDirectoryFileStore(config_obj) @@ -58,12 +59,12 @@ func GetFileStoreFileSystemAccessor( switch config_obj.Datastore.Implementation { case "FileBaseDataStore": - return api.NewFileStoreFileSystemAccessor( + return accessors.NewFileStoreFileSystemAccessor( config_obj, directory.NewDirectoryFileStore(config_obj)), nil case "Test": - return api.NewFileStoreFileSystemAccessor( - config_obj, memory.Test_memory_file_store), nil + return accessors.NewFileStoreFileSystemAccessor( + config_obj, memory.NewMemoryFileStore(config_obj)), nil } diff --git a/file_store/memory/memory.go b/file_store/memory/memory.go index 10527234d5c..ff2c774644f 100644 --- a/file_store/memory/memory.go +++ b/file_store/memory/memory.go @@ -7,36 +7,56 @@ import ( "os" "path" "path/filepath" + "runtime" "strings" "sync" "github.com/Velocidex/ordereddict" "github.com/pkg/errors" + config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/file_store/api" - "www.velocidex.com/golang/velociraptor/glob" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/utils" "www.velocidex.com/golang/velociraptor/vtesting" ) var ( // Only used for tests. - Test_memory_file_store *MemoryFileStore = &MemoryFileStore{ - Data: ordereddict.NewDict(), - } + Test_memory_file_store *MemoryFileStore ) +func NewMemoryFileStore(config_obj *config_proto.Config) *MemoryFileStore { + mu.Lock() + defer mu.Unlock() + + if Test_memory_file_store == nil { + Test_memory_file_store = &MemoryFileStore{ + Data: ordereddict.NewDict(), + config_obj: config_obj, + } + } + + // Sanitize the FilestoreDirectory + config_obj.Datastore.FilestoreDirectory = strings.TrimSuffix( + config_obj.Datastore.FilestoreDirectory, "/") + + return Test_memory_file_store +} + type MemoryReader struct { *bytes.Reader - filename string + pathSpec_ api.FSPathSpec + filename string } func (self MemoryReader) Close() error { return nil } -func (self MemoryReader) Stat() (glob.FileInfo, error) { +func (self MemoryReader) Stat() (api.FileInfo, error) { return vtesting.MockFileInfo{ Name_: self.filename, + PathSpec_: self.pathSpec_, FullPath_: self.filename, Size_: int64(self.Reader.Len()), }, nil @@ -73,7 +93,8 @@ func (self *MemoryWriter) Truncate() error { type MemoryFileStore struct { mu sync.Mutex - Data *ordereddict.Dict + config_obj *config_proto.Config + Data *ordereddict.Dict } func (self *MemoryFileStore) Debug() { @@ -96,26 +117,31 @@ func (self *MemoryFileStore) Debug() { } } -func (self *MemoryFileStore) ReadFile(filename string) (api.FileReader, error) { +func (self *MemoryFileStore) ReadFile(path api.FSPathSpec) (api.FileReader, error) { self.mu.Lock() defer self.mu.Unlock() + filename := pathSpecToPath(path, self.config_obj) + self.Trace("ReadFile", filename) data_any, pres := self.Data.Get(filename) if pres { data := data_any.([]byte) return MemoryReader{ - Reader: bytes.NewReader(data), - filename: filename, + Reader: bytes.NewReader(data), + pathSpec_: path, + filename: filename, }, nil } return nil, errors.New("Not found") } -func (self *MemoryFileStore) WriteFile(filename string) (api.FileWriter, error) { +func (self *MemoryFileStore) WriteFile(path api.FSPathSpec) (api.FileWriter, error) { self.mu.Lock() defer self.mu.Unlock() + filename := pathSpecToPath(path, self.config_obj) + self.Trace("WriteFile", filename) buf, pres := self.Data.Get(filename) if !pres { buf = []byte{} @@ -129,41 +155,47 @@ func (self *MemoryFileStore) WriteFile(filename string) (api.FileWriter, error) }, nil } -func (self *MemoryFileStore) StatFile(filename string) (os.FileInfo, error) { +func (self *MemoryFileStore) StatFile(path api.FSPathSpec) (api.FileInfo, error) { self.mu.Lock() defer self.mu.Unlock() + filename := pathSpecToPath(path, self.config_obj) + self.Trace("StatFile", filename) buff, pres := self.Data.Get(filename) if !pres { return nil, os.ErrNotExist } return &vtesting.MockFileInfo{ - Name_: path.Base(filename), + Name_: path.Base(), FullPath_: filename, Size_: int64(len(buff.([]byte))), }, nil } -func (self *MemoryFileStore) Move(src, dest string) error { +func (self *MemoryFileStore) Move(src, dest api.FSPathSpec) error { self.mu.Lock() defer self.mu.Unlock() - buff, pres := self.Data.Get(src) + src_filename := pathSpecToPath(src, self.config_obj) + dest_filename := pathSpecToPath(dest, self.config_obj) + buff, pres := self.Data.Get(src_filename) if !pres { return os.ErrNotExist } - self.Data.Set(dest, buff) - self.Data.Delete(src) + self.Data.Set(dest_filename, buff) + self.Data.Delete(src_filename) return nil } -func (self *MemoryFileStore) ListDirectory(dirname string) ([]os.FileInfo, error) { +func (self *MemoryFileStore) ListDirectory(path api.FSPathSpec) ([]api.FileInfo, error) { self.mu.Lock() defer self.mu.Unlock() - result := []os.FileInfo{} + dirname := pathDirSpecToPath(path, self.config_obj) + self.Trace("ListDirectory", dirname) + result := []api.FileInfo{} files := []string{} for _, filename := range self.Data.Keys() { v_any, _ := self.Data.Get(filename) @@ -175,27 +207,39 @@ func (self *MemoryFileStore) ListDirectory(dirname string) ([]os.FileInfo, error components := strings.Split(k, "/") if len(components) > 0 && !utils.InString(files, components[0]) { + name := utils.UnsanitizeComponent(components[0]) + + if strings.HasSuffix(name, ".db") { + continue + } + + name_type, name := api.GetFileStorePathTypeFromExtension(name) + child := path.AddChild(name).SetType(name_type) + result = append(result, &vtesting.MockFileInfo{ - Name_: components[0], - FullPath_: path.Join(dirname, components[0]), + Name_: name, + PathSpec_: child, + FullPath_: child.AsClientPath(), Size_: int64(len(v)), }) - files = append(files, components[0]) + files = append(files, name) } } } return result, nil } -func (self *MemoryFileStore) Walk(root string, walkFn filepath.WalkFunc) error { +func (self *MemoryFileStore) Walk( + root api.FSPathSpec, walkFn api.WalkFunc) error { children, err := self.ListDirectory(root) if err != nil { return err } for _, child_info := range children { - full_path := path.Join(root, child_info.Name()) - err1 := walkFn(full_path, child_info, err) + full_path := root.AddChild(utils.UnsanitizeComponent( + child_info.Name())) + err1 := walkFn(full_path, child_info) if err1 == filepath.SkipDir { continue } @@ -209,19 +253,26 @@ func (self *MemoryFileStore) Walk(root string, walkFn filepath.WalkFunc) error { return nil } -func (self *MemoryFileStore) Delete(filename string) error { +func (self *MemoryFileStore) Delete(path api.FSPathSpec) error { self.mu.Lock() defer self.mu.Unlock() + filename := pathSpecToPath(path, self.config_obj) + self.Trace("Delete", filename) self.Data.Delete(filename) return nil } +func (self *MemoryFileStore) Trace(name, filename string) { + return + fmt.Printf("Trace MemoryFileStore: %v: %v\n", name, filename) +} + func (self *MemoryFileStore) Get(filename string) ([]byte, bool) { self.mu.Lock() defer self.mu.Unlock() - res, pres := self.Data.Get(filename) + res, pres := self.Data.Get(cleanPathForWindows(filename)) if pres { return res.([]byte), pres } @@ -234,3 +285,24 @@ func (self *MemoryFileStore) Clear() { self.Data = ordereddict.NewDict() } + +func pathSpecToPath( + p api.FSPathSpec, config_obj *config_proto.Config) string { + return cleanPathForWindows(p.AsFilestoreFilename(config_obj)) +} + +func cleanPathForWindows(result string) string { + // Sanitize it on windows to convert back to a common format + // for comparisons. + if runtime.GOOS == "windows" { + return path.Clean(strings.Replace(strings.TrimPrefix( + result, path_specs.WINDOWS_LFN_PREFIX), "\\", "/", -1)) + } + + return result +} + +func pathDirSpecToPath(p api.FSPathSpec, + config_obj *config_proto.Config) string { + return cleanPathForWindows(p.AsFilestoreDirectory(config_obj)) +} diff --git a/file_store/memory/memory_component.go b/file_store/memory/memory_component.go new file mode 100644 index 00000000000..81d4fdda942 --- /dev/null +++ b/file_store/memory/memory_component.go @@ -0,0 +1,131 @@ +package memory + +import ( + "bytes" + "os" + "path" + "path/filepath" + "runtime" + "strings" + + "github.com/pkg/errors" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/utils" + "www.velocidex.com/golang/velociraptor/vtesting" +) + +const ( + // On windows all file paths must be prefixed by this to + // support long paths. + WINDOWS_LFN_PREFIX = "\\\\?\\" +) + +func (self *MemoryFileStore) ComponentsToFileStorePath( + components []string) string { + sanitized_components := make([]string, 0, len(components)) + for _, component := range components { + sanitized_components = append(sanitized_components, + string(utils.SanitizeString(component))) + } + + // OS filenames may use / or \ as separators. On windows we + // prefix the LFN prefix to be able to access long paths but + // then we must use \ as a separator. + result := filepath.Join(sanitized_components...) + + if runtime.GOOS == "windows" { + return WINDOWS_LFN_PREFIX + result + } + return result +} + +func (self *MemoryFileStore) ReadFileComponents( + components []string) (api.FileReader, error) { + self.mu.Lock() + defer self.mu.Unlock() + + filename := self.ComponentsToFileStorePath(components) + data_any, pres := self.Data.Get(filename) + if pres { + data := data_any.([]byte) + return MemoryReader{ + Reader: bytes.NewReader(data), + filename: filename, + }, nil + } + + return nil, errors.New("Not found") +} + +func (self *MemoryFileStore) WriteFileComponent( + components []string) (api.FileWriter, error) { + self.mu.Lock() + defer self.mu.Unlock() + + filename := self.ComponentsToFileStorePath(components) + buf, pres := self.Data.Get(filename) + if !pres { + buf = []byte{} + } + self.Data.Set(filename, buf) + + return &MemoryWriter{ + buf: buf.([]byte), + memory_file_store: self, + filename: filename, + }, nil +} + +func (self *MemoryFileStore) StatFileComponents( + components []string) (os.FileInfo, error) { + self.mu.Lock() + defer self.mu.Unlock() + + filename := self.ComponentsToFileStorePath(components) + buff, pres := self.Data.Get(filename) + if !pres { + return nil, os.ErrNotExist + } + + return &vtesting.MockFileInfo{ + Name_: path.Base(filename), + FullPath_: filename, + Size_: int64(len(buff.([]byte))), + }, nil +} + +func (self *MemoryFileStore) ListDirectoryComponents( + path_components []string) ([]os.FileInfo, error) { + self.mu.Lock() + defer self.mu.Unlock() + + dirname := self.ComponentsToFileStorePath(path_components) + result := []os.FileInfo{} + files := []string{} + for _, filename := range self.Data.Keys() { + v_any, _ := self.Data.Get(filename) + v := v_any.([]byte) + + if strings.HasPrefix(filename, dirname) { + k := strings.TrimLeft( + strings.TrimPrefix(filename, dirname), "/") + components := strings.Split(k, "/") + if len(components) > 0 && + !utils.InString(files, components[0]) { + new_components := append( + make([]string, 0, len(path_components)), + path_components...) + + result = append(result, &vtesting.MockFileInfo{ + Name_: components[0], + // Make a new copy for each child. + Components: append(new_components, + components[0]), + Size_: int64(len(v)), + }) + files = append(files, components[0]) + } + } + } + return result, nil +} diff --git a/file_store/memory/queue.go b/file_store/memory/queue.go index 3ea81b9e750..2001bad66a0 100644 --- a/file_store/memory/queue.go +++ b/file_store/memory/queue.go @@ -15,6 +15,7 @@ import ( "github.com/Velocidex/ordereddict" config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/tests" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/result_sets" "www.velocidex.com/golang/velociraptor/utils" @@ -143,7 +144,7 @@ type MemoryQueueManager struct { func (self *MemoryQueueManager) Debug() { switch t := self.FileStore.(type) { - case api.Debugger: + case tests.Debugger: t.Debug() } } diff --git a/file_store/memory/queue_test.go b/file_store/memory/queue_test.go index 2dfe682b411..d91512a99a4 100644 --- a/file_store/memory/queue_test.go +++ b/file_store/memory/queue_test.go @@ -5,8 +5,8 @@ import ( "github.com/stretchr/testify/suite" "www.velocidex.com/golang/velociraptor/config" - "www.velocidex.com/golang/velociraptor/file_store/api" "www.velocidex.com/golang/velociraptor/file_store/memory" + "www.velocidex.com/golang/velociraptor/file_store/tests" _ "www.velocidex.com/golang/velociraptor/result_sets/simple" _ "www.velocidex.com/golang/velociraptor/result_sets/timed" @@ -14,6 +14,7 @@ import ( func TestMemoryQueueManager(t *testing.T) { config_obj := config.GetDefaultConfig() - manager := memory.NewMemoryQueueManager(config_obj, memory.Test_memory_file_store) - suite.Run(t, api.NewQueueManagerTestSuite(config_obj, manager, memory.Test_memory_file_store)) + file_store := memory.NewMemoryFileStore(config_obj) + manager := memory.NewMemoryQueueManager(config_obj, file_store) + suite.Run(t, tests.NewQueueManagerTestSuite(config_obj, manager, file_store)) } diff --git a/file_store/path_specs/fs_path_spec.go b/file_store/path_specs/fs_path_spec.go new file mode 100644 index 00000000000..1693d701617 --- /dev/null +++ b/file_store/path_specs/fs_path_spec.go @@ -0,0 +1,89 @@ +package path_specs + +import ( + config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/utils" +) + +type FSPathSpec struct { + DSPathSpec +} + +func (self FSPathSpec) Dir() api.FSPathSpec { + new_components := utils.CopySlice(self.components) + if len(new_components) > 0 { + new_components = new_components[:len(new_components)-1] + } + return FSPathSpec{DSPathSpec{ + components: new_components, + path_type: self.path_type, + }} +} + +// Adds an unsafe component to this path. +func (self FSPathSpec) AddChild(child ...string) api.FSPathSpec { + return FSPathSpec{DSPathSpec{ + components: append(utils.CopySlice(self.components), child...), + path_type: self.path_type, + is_safe: self.is_safe, + }} +} + +func (self FSPathSpec) AddUnsafeChild(child ...string) api.FSPathSpec { + return FSPathSpec{DSPathSpec{ + components: append(utils.CopySlice(self.components), child...), + path_type: self.path_type, + is_safe: false, + }} +} + +func (self FSPathSpec) SetType(ext api.PathType) api.FSPathSpec { + return FSPathSpec{DSPathSpec{ + components: self.components, + path_type: ext, + is_safe: self.is_safe, + }} +} + +func (self FSPathSpec) AsFilestoreFilename( + config_obj *config_proto.Config) string { + return self.AsFilestoreDirectory(config_obj) + + api.GetExtensionForFilestore(self, self.path_type) +} + +func (self FSPathSpec) AsFilestoreDirectory( + config_obj *config_proto.Config) string { + if self.is_safe { + return self.asSafeDirWithRoot( + config_obj.Datastore.FilestoreDirectory) + } + return self.asUnsafeDirWithRoot( + config_obj.Datastore.FilestoreDirectory) +} + +func (self FSPathSpec) AsClientPath() string { + return utils.JoinComponents(self.components, "/") + + api.GetExtensionForFilestore(self, self.path_type) +} + +func NewUnsafeFilestorePath(path_components ...string) api.FSPathSpec { + result := FSPathSpec{DSPathSpec{ + components: path_components, + // By default write JSON files. + path_type: api.PATH_TYPE_FILESTORE_JSON, + is_safe: false, + }} + + return result +} + +func NewSafeFilestorePath(path_components ...string) api.FSPathSpec { + result := FSPathSpec{DSPathSpec{ + components: path_components, + path_type: api.PATH_TYPE_FILESTORE_JSON, + is_safe: true, + }} + + return result +} diff --git a/file_store/path_specs/path_specs.go b/file_store/path_specs/path_specs.go new file mode 100644 index 00000000000..9cb59629eb2 --- /dev/null +++ b/file_store/path_specs/path_specs.go @@ -0,0 +1,162 @@ +package path_specs + +import ( + "path/filepath" + "runtime" + "strconv" + "strings" + + config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/utils" +) + +const ( + WINDOWS_LFN_PREFIX = "\\\\?\\" +) + +type DSPathSpec struct { + components []string + path_type api.PathType + + // If this is true we can avoid sanitizing the path on writing + // to the filestore. + is_safe bool +} + +func (self DSPathSpec) MarshalJSON() ([]byte, error) { + return []byte(strconv.Quote(self.AsClientPath())), nil +} + +func (self DSPathSpec) Base() string { + return self.components[len(self.components)-1] +} + +func (self DSPathSpec) Dir() api.DSPathSpec { + new_components := utils.CopySlice(self.components) + if len(new_components) > 0 { + new_components = new_components[:len(new_components)-1] + } + return &DSPathSpec{ + components: new_components, + path_type: self.path_type, + } +} + +func (self DSPathSpec) Components() []string { + return self.components +} + +func (self DSPathSpec) Type() api.PathType { + return self.path_type +} + +// Adds an unsafe component to this path. +func (self DSPathSpec) AddChild(child ...string) api.DSPathSpec { + return DSPathSpec{ + components: append(utils.CopySlice(self.components), child...), + path_type: self.path_type, + is_safe: self.is_safe, + } +} + +func (self DSPathSpec) AddUnsafeChild(child ...string) api.DSPathSpec { + return DSPathSpec{ + components: append(utils.CopySlice(self.components), child...), + path_type: self.path_type, + is_safe: false, + } +} + +func (self DSPathSpec) SetType(ext api.PathType) api.DSPathSpec { + return DSPathSpec{ + components: self.components, + path_type: ext, + is_safe: self.is_safe, + } +} + +func (self DSPathSpec) AsClientPath() string { + return utils.JoinComponents(self.components, "/") + + api.GetExtensionForDatastore(self, self.path_type) +} + +func (self DSPathSpec) AsDatastoreDirectory( + config_obj *config_proto.Config) string { + if self.is_safe { + return self.asSafeDirWithRoot(config_obj.Datastore.Location) + } + return self.asUnsafeDirWithRoot(config_obj.Datastore.Location) +} + +// When we are unsafe we need to Sanitize components hitting the +// filesystem. +func (self DSPathSpec) asUnsafeDirWithRoot(root string) string { + sep := string(filepath.Separator) + new_components := make([]string, 0, len(self.components)) + for _, i := range self.components { + new_components = append(new_components, utils.SanitizeString(i)) + } + result := sep + strings.Join(new_components, sep) + + // This relies on the filepath starting with a drive letter + // and having \ as path separators. Main's + // validateServerConfig() ensures this is the case. + if runtime.GOOS == "windows" { + return "\\\\?\\" + root + result + } + return root + result +} + +func (self DSPathSpec) AsDatastoreFilename( + config_obj *config_proto.Config) string { + return self.AsDatastoreDirectory(config_obj) + + api.GetExtensionForDatastore(self, self.path_type) +} + +func (self DSPathSpec) AsFilestorePath() api.FSPathSpec { + return &FSPathSpec{DSPathSpec{ + components: self.components, + path_type: api.PATH_TYPE_FILESTORE_JSON, + is_safe: self.is_safe, + }} +} + +func NewUnsafeDatastorePath(path_components ...string) DSPathSpec { + result := DSPathSpec{ + components: path_components, + // By default write JSON files. + path_type: api.PATH_TYPE_DATASTORE_JSON, + is_safe: false, + } + + return result +} + +func NewSafeDatastorePath(path_components ...string) DSPathSpec { + result := DSPathSpec{ + components: path_components, + path_type: api.PATH_TYPE_DATASTORE_JSON, + is_safe: true, + } + + return result +} + +// If the path spec is already safe we can shortcut it and not +// sanitize. +func (self DSPathSpec) asSafeDirWithRoot(root string) string { + // No need to sanitize here because the DSPathSpec is already + // safe. + sep := string(filepath.Separator) + result := sep + strings.Join(self.components, sep) + + // This relies on the filepath starting with a drive letter + // and having \ as path separators, and having a trailing + // \. Main's config.ValidateDatastoreConfig() ensures this is + // the case. + if runtime.GOOS == "windows" { + return WINDOWS_LFN_PREFIX + root + result + } + return root + result +} diff --git a/file_store/path_specs/utils.go b/file_store/path_specs/utils.go new file mode 100644 index 00000000000..42d5959bbac --- /dev/null +++ b/file_store/path_specs/utils.go @@ -0,0 +1,26 @@ +package path_specs + +import ( + "strings" + + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/utils" +) + +func CleanPathForZip(path_spec api.FSPathSpec, client_id, hostname string) string { + components := path_spec.Components() + hostname = utils.SanitizeString(hostname) + result := make([]string, 0, len(components)) + for _, component := range components { + // Replace any client id with hostnames + if component == client_id { + component = hostname + } + + result = append(result, utils.SanitizeString(component)) + } + + // Zip files should not have absolute paths + return strings.Join(result, "/") + api.GetExtensionForFilestore( + path_spec, path_spec.Type()) +} diff --git a/file_store/test_utils/testing.go b/file_store/test_utils/testing.go index 6012b46cbc4..99829f41ccb 100644 --- a/file_store/test_utils/testing.go +++ b/file_store/test_utils/testing.go @@ -9,6 +9,7 @@ import ( config_proto "www.velocidex.com/golang/velociraptor/config/proto" "www.velocidex.com/golang/velociraptor/datastore" "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/file_store/api" "www.velocidex.com/golang/velociraptor/file_store/memory" "www.velocidex.com/golang/velociraptor/utils" ) @@ -31,7 +32,8 @@ func GetMemoryDataStore( return db.(*datastore.TestDataStore) } -func FileReadAll(t *testing.T, config_obj *config_proto.Config, vfs_path string) string { +func FileReadAll(t *testing.T, config_obj *config_proto.Config, + vfs_path api.FSPathSpec) string { file_store_factory := file_store.GetFileStore(config_obj) fd, err := file_store_factory.ReadFile(vfs_path) require.NoError(t, err) @@ -45,7 +47,7 @@ func FileReadAll(t *testing.T, config_obj *config_proto.Config, vfs_path string) } func FileReadRows(t *testing.T, config_obj *config_proto.Config, - vfs_path string) []*ordereddict.Dict { + vfs_path api.FSPathSpec) []*ordereddict.Dict { data := FileReadAll(t, config_obj, vfs_path) res, err := utils.ParseJsonToDicts([]byte(data)) diff --git a/file_store/api/testsuite.go b/file_store/tests/testsuite.go similarity index 60% rename from file_store/api/testsuite.go rename to file_store/tests/testsuite.go index 7ae5dbe64b0..12e39602fe4 100644 --- a/file_store/api/testsuite.go +++ b/file_store/tests/testsuite.go @@ -1,6 +1,6 @@ //nolint -package api +package tests import ( "context" @@ -8,13 +8,14 @@ import ( "io" "io/ioutil" "os" - "path" "sort" "github.com/Velocidex/ordereddict" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" config_proto "www.velocidex.com/golang/velociraptor/config/proto" + "www.velocidex.com/golang/velociraptor/file_store/api" + "www.velocidex.com/golang/velociraptor/file_store/path_specs" "www.velocidex.com/golang/velociraptor/utils" ) @@ -28,11 +29,11 @@ type FileStoreTestSuite struct { suite.Suite config_obj *config_proto.Config - filestore FileStore + filestore api.FileStore } func NewFileStoreTestSuite(config_obj *config_proto.Config, - filestore FileStore) *FileStoreTestSuite { + filestore api.FileStore) *FileStoreTestSuite { return &FileStoreTestSuite{ config_obj: config_obj, filestore: filestore, @@ -40,11 +41,13 @@ func NewFileStoreTestSuite(config_obj *config_proto.Config, } func (self *FileStoreTestSuite) TestListChildrenIntermediateDirs() { - fd, err := self.filestore.WriteFile("/a/b/c/d/Foo") + components := path_specs.NewSafeFilestorePath("a", "b", "c", "d", "Foo") + fd, err := self.filestore.WriteFile(components) assert.NoError(self.T(), err) defer fd.Close() - infos, err := self.filestore.ListDirectory("/a") + infos, err := self.filestore.ListDirectory( + path_specs.NewSafeFilestorePath("a")) assert.NoError(self.T(), err) names := []string{} @@ -56,17 +59,80 @@ func (self *FileStoreTestSuite) TestListChildrenIntermediateDirs() { assert.Equal(self.T(), names, []string{"b"}) } +// List children recovers child's type based on extensions. +func (self *FileStoreTestSuite) TestListChildrenWithTypes() { + + for idx, t := range []api.PathType{ + api.PATH_TYPE_FILESTORE_JSON_INDEX, + api.PATH_TYPE_FILESTORE_JSON, + api.PATH_TYPE_FILESTORE_JSON_TIME_INDEX, + + // Used to write sparse indexes + api.PATH_TYPE_FILESTORE_SPARSE_IDX, + + // Used to write zip files in the download folder. + api.PATH_TYPE_FILESTORE_DOWNLOAD_ZIP, + api.PATH_TYPE_FILESTORE_DOWNLOAD_REPORT, + + // TMP files + api.PATH_TYPE_FILESTORE_TMP, + api.PATH_TYPE_FILESTORE_LOCK, + api.PATH_TYPE_FILESTORE_CSV, + + // Used for artifacts + api.PATH_TYPE_FILESTORE_YAML, + + api.PATH_TYPE_FILESTORE_ANY, + } { + filename := path_specs.NewSafeFilestorePath( + "a", fmt.Sprintf("b%v", idx)).SetType(t) + + fd, err := self.filestore.WriteFile(filename.AddChild("Foo.txt")) + assert.NoError(self.T(), err) + defer fd.Close() + + infos, err := self.filestore.ListDirectory(filename) + assert.NoError(self.T(), err) + + assert.Equal(self.T(), 1, len(infos)) + + // The type should be correct. + assert.Equal(self.T(), t, infos[0].PathSpec().Type()) + + // The extension should be correctly stripped so the + // filename is roundtripped. + assert.Equal(self.T(), infos[0].Name(), "Foo.txt") + + // Now check walk + path_specs := []api.FSPathSpec{} + err = self.filestore.Walk(filename, func( + path api.FSPathSpec, info os.FileInfo) error { + // Ignore directories as they are not important. + if !info.IsDir() { + path_specs = append(path_specs, path) + } + return nil + }) + assert.NoError(self.T(), err) + + assert.Equal(self.T(), 1, len(path_specs)) + + // The type should be correct. + assert.Equal(self.T(), t, path_specs[0].Type()) + } +} + func (self *FileStoreTestSuite) TestListChildren() { - filename := "/a/b" - fd, err := self.filestore.WriteFile(path.Join(filename, "Foo.txt")) + filename := path_specs.NewSafeFilestorePath("a", "b") + fd, err := self.filestore.WriteFile(filename.AddChild("Foo.txt")) assert.NoError(self.T(), err) defer fd.Close() - fd, err = self.filestore.WriteFile(path.Join(filename, "Bar.txt")) + fd, err = self.filestore.WriteFile(filename.AddChild("Bar.txt")) assert.NoError(self.T(), err) defer fd.Close() - fd, err = self.filestore.WriteFile(path.Join(filename, "Bar", "Baz")) + fd, err = self.filestore.WriteFile(filename.AddChild("Bar", "Baz")) assert.NoError(self.T(), err) defer fd.Close() @@ -82,34 +148,35 @@ func (self *FileStoreTestSuite) TestListChildren() { assert.Equal(self.T(), names, []string{"Bar", "Bar.txt", "Foo.txt"}) names = nil - err = self.filestore.Walk(filename, func(path string, info os.FileInfo, err error) error { - // Ignore directories as they are not important. - if !info.IsDir() { - names = append(names, path) - } + err = self.filestore.Walk(filename, func( + path api.FSPathSpec, info os.FileInfo) error { + names = append(names, path.AsClientPath()) return nil }) assert.NoError(self.T(), err) sort.Strings(names) - fmt.Println(names) - assert.Equal(self.T(), names, []string{ - "/a/b/Bar.txt", - "/a/b/Bar/Baz", - "/a/b/Foo.txt"}) + // AsClientPath() restores the extension. + assert.Equal(self.T(), []string{ + "/a/b/Bar.txt.json", + "/a/b/Bar/Baz.json", + "/a/b/Foo.txt.json"}, names) // Walk non existent directory just returns no results. names = nil - err = self.filestore.Walk(filename+"/nonexistant", func(path string, info os.FileInfo, err error) error { - names = append(names, path) - return nil - }) + err = self.filestore.Walk(filename.AddChild("nonexistant"), + func(path api.FSPathSpec, info os.FileInfo) error { + names = append(names, path.AsFilestoreFilename( + self.config_obj)) + return nil + }) assert.NoError(self.T(), err) assert.Equal(self.T(), len(names), 0) } func (self *FileStoreTestSuite) TestFileReadWrite() { - fd, err := self.filestore.WriteFile("/test/foo") + filename := path_specs.NewSafeFilestorePath("test", "foo") + fd, err := self.filestore.WriteFile(filename) assert.NoError(self.T(), err) defer fd.Close() @@ -126,7 +193,7 @@ func (self *FileStoreTestSuite) TestFileReadWrite() { assert.NoError(self.T(), err) buff := make([]byte, 6) - reader, err := self.filestore.ReadFile("/test/foo") + reader, err := self.filestore.ReadFile(filename) assert.NoError(self.T(), err) defer reader.Close() @@ -206,7 +273,7 @@ func (self *FileStoreTestSuite) TestFileReadWrite() { assert.NoError(self.T(), err) assert.Equal(self.T(), int64(29), size) - fd, err = self.filestore.WriteFile("/test/foo") + fd, err = self.filestore.WriteFile(filename) assert.NoError(self.T(), err) size, err = fd.Size() assert.NoError(self.T(), err) @@ -217,8 +284,8 @@ type QueueManagerTestSuite struct { suite.Suite config_obj *config_proto.Config - manager QueueManager - file_store FileStore + manager api.QueueManager + file_store api.FileStore } func (self *QueueManagerTestSuite) Debug() { @@ -228,9 +295,11 @@ func (self *QueueManagerTestSuite) Debug() { } } -func (self *QueueManagerTestSuite) FilestoreGet(path string) string { - fd, _ := self.file_store.ReadFile(path) - value, _ := ioutil.ReadAll(fd) +func (self *QueueManagerTestSuite) FilestoreGet(path api.FSPathSpec) string { + fd, err := self.file_store.ReadFile(path) + assert.NoError(self.T(), err) + value, err := ioutil.ReadAll(fd) + assert.NoError(self.T(), err) return string(value) } @@ -245,8 +314,10 @@ func (self *QueueManagerTestSuite) TestPush() { output, cancel := self.manager.Watch(ctx, artifact_name) defer cancel() + log_path := path_specs.NewUnsafeFilestorePath("log_path") err := self.manager.PushEventRows( - MockPathManager{"log_path", artifact_name}, payload) + MockPathManager{log_path, artifact_name}, + payload) assert.NoError(self.T(), err) @@ -262,13 +333,13 @@ func (self *QueueManagerTestSuite) TestPush() { } // Make sure the manager wrote the event to the filestore as well. - assert.Contains(self.T(), self.FilestoreGet("log_path"), "foo") + assert.Contains(self.T(), self.FilestoreGet(log_path), "foo") } func NewQueueManagerTestSuite( config_obj *config_proto.Config, - manager QueueManager, - file_store FileStore) *QueueManagerTestSuite { + manager api.QueueManager, + file_store api.FileStore) *QueueManagerTestSuite { return &QueueManagerTestSuite{ config_obj: config_obj, manager: manager, @@ -277,11 +348,11 @@ func NewQueueManagerTestSuite( } type MockPathManager struct { - Path string + Path api.FSPathSpec ArtifactName string } -func (self MockPathManager) GetPathForWriting() (string, error) { +func (self MockPathManager) GetPathForWriting() (api.FSPathSpec, error) { return self.Path, nil } @@ -290,6 +361,6 @@ func (self MockPathManager) GetQueueName() string { } func (self MockPathManager) GetAvailableFiles( - ctx context.Context) []*ResultSetFileProperties { + ctx context.Context) []*api.ResultSetFileProperties { return nil } diff --git a/file_store/utils.go b/file_store/utils.go index 5a5c4b20c2d..ceae30552d3 100644 --- a/file_store/utils.go +++ b/file_store/utils.go @@ -8,13 +8,13 @@ import ( ) func PushRows(config_obj *config_proto.Config, - path_manager api.PathManager, + path api.FSPathSpec, rows []*ordereddict.Dict) error { file_store_factory := GetFileStore(config_obj) rs_writer, err := result_sets.NewResultSetWriter(file_store_factory, - path_manager, nil, false /* truncate */) + path, nil, false /* truncate */) if err != nil { return err } diff --git a/flows/api.go b/flows/api.go index 8fe6172deed..7c2580384ca 100644 --- a/flows/api.go +++ b/flows/api.go @@ -19,7 +19,6 @@ package flows import ( "context" - "path" "sort" "strings" "time" @@ -32,6 +31,7 @@ import ( crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto" "www.velocidex.com/golang/velociraptor/datastore" "www.velocidex.com/golang/velociraptor/file_store" + "www.velocidex.com/golang/velociraptor/file_store/api" flows_proto "www.velocidex.com/golang/velociraptor/flows/proto" "www.velocidex.com/golang/velociraptor/logging" "www.velocidex.com/golang/velociraptor/paths" @@ -75,7 +75,7 @@ func GetFlows( // Flow IDs represent timestamp so they are sortable. The UI // relies on more recent flows being at the top. sort.Slice(flow_urns, func(i, j int) bool { - return flow_urns[i] > flow_urns[j] + return flow_urns[i].Base() > flow_urns[j].Base() }) // Collect the items that match from this backend read @@ -84,7 +84,7 @@ func GetFlows( for _, urn := range flow_urns { // Hide the monitoring flow since it is not a real flow. - if strings.HasSuffix(urn, constants.MONITORING_WELL_KNOWN_FLOW) { + if urn.Base() == constants.MONITORING_WELL_KNOWN_FLOW { continue } @@ -170,14 +170,14 @@ func availableDownloadFiles(config_obj *config_proto.Config, client_id string, flow_id string) (*api_proto.AvailableDownloads, error) { flow_path_manager := paths.NewFlowPathManager(client_id, flow_id) - download_file := flow_path_manager.GetDownloadsFile("").Path() - download_path := path.Dir(download_file) + download_file := flow_path_manager.GetDownloadsFile("X") + download_path := download_file.Dir() return getAvailableDownloadFiles(config_obj, download_path) } func getAvailableDownloadFiles(config_obj *config_proto.Config, - download_path string) (*api_proto.AvailableDownloads, error) { + download_path api.FSPathSpec) (*api_proto.AvailableDownloads, error) { result := &api_proto.AvailableDownloads{} file_store_factory := file_store.GetFileStore(config_obj) @@ -202,8 +202,9 @@ func getAvailableDownloadFiles(config_obj *config_proto.Config, } result.Files = append(result.Files, &api_proto.AvailableDownloadFile{ - Name: item.Name(), - Path: path.Join(download_path, item.Name()), + Name: item.Name(), + Path: download_path.AddChild( + item.Name()).AsClientPath(), Size: uint64(item.Size()), Date: item.ModTime().UTC().Format(time.RFC3339), Complete: is_complete(item.Name()), @@ -350,8 +351,8 @@ func GetFlowRequests( flow_path_manager := paths.NewFlowPathManager(client_id, flow_id) flow_details := &api_proto.ApiFlowRequestDetails{} - err = db.GetSubject(config_obj, flow_path_manager.Task().Path(), - flow_details) + err = db.GetSubject( + config_obj, flow_path_manager.Task(), flow_details) if err != nil { return nil, err } diff --git a/flows/artifacts.go b/flows/artifacts.go index f237d72f6ca..8aca282df3b 100644 --- a/flows/artifacts.go +++ b/flows/artifacts.go @@ -329,7 +329,9 @@ func ArtifactCollectorProcessOneMessage( file_store_factory := file_store.GetFileStore(config_obj) rs_writer, err := result_sets.NewResultSetWriter( - file_store_factory, path_manager, nil, false /* truncate */) + file_store_factory, + path_manager.Path(), + nil, false /* truncate */) if err != nil { return err } @@ -469,7 +471,7 @@ func appendUploadDataToFile( // otherwise the flow will be terminated. Log(config_obj, collection_context, fmt.Sprintf("While writing to %v: %v", - file_path_manager.Path(), err)) + file_path_manager.Path().AsClientPath(), err)) return nil } defer fd.Close() @@ -494,7 +496,8 @@ func appendUploadDataToFile( collection_context.UploadedFiles = append( collection_context.UploadedFiles, &flows_proto.ArtifactUploadedFileInfo{ - Name: file_path_manager.Path(), + Name: file_path_manager.Path().AsClientPath(), + Components: file_path_manager.Path().Components(), Size: file_buffer.Size, StoredSize: size, }) @@ -510,13 +513,14 @@ func appendUploadDataToFile( if err != nil { Log(config_obj, collection_context, fmt.Sprintf("While writing to %v: %v", - file_path_manager.Path(), err)) + file_path_manager.Path().AsClientPath(), err)) return nil } // Does this packet have an index? It could be sparse. if file_buffer.Index != nil { - fd, err := file_store_factory.WriteFile(file_path_manager.IndexPath()) + fd, err := file_store_factory.WriteFile( + file_path_manager.IndexPath()) if err != nil { return err } @@ -536,7 +540,10 @@ func appendUploadDataToFile( collection_context.UploadedFiles = append( collection_context.UploadedFiles, &flows_proto.ArtifactUploadedFileInfo{ - Name: file_path_manager.IndexPath(), + Name: file_path_manager.IndexPath(). + AsClientPath(), + Components: file_path_manager.IndexPath(). + Components(), Size: uint64(len(data)), StoredSize: uint64(len(data)), }) @@ -551,7 +558,7 @@ func appendUploadDataToFile( row := ordereddict.NewDict(). Set("Timestamp", time.Now().UTC().Unix()). Set("ClientId", message.Source). - Set("VFSPath", file_path_manager.Path()). + Set("VFSPath", file_path_manager.Path().AsClientPath()). Set("UploadName", file_buffer.Pathspec.Path). Set("Accessor", file_buffer.Pathspec.Accessor). Set("Size", file_buffer.Size). diff --git a/flows/artifacts_test.go b/flows/artifacts_test.go index bc9e3fd31bb..0ea35636cdd 100644 --- a/flows/artifacts_test.go +++ b/flows/artifacts_test.go @@ -443,13 +443,14 @@ func (self *TestSuite) TestClientUploaderStoreFile() { // Check the upload metadata file. upload_metadata_rows := test_utils.FileReadRows(self.T(), self.config_obj, - flow_path_manager.UploadMetadata().Path()) + flow_path_manager.UploadMetadata()) assert.Equal(self.T(), len(upload_metadata_rows), 1) vfs_path, _ := upload_metadata_rows[0].GetString("vfs_path") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "foo").Path()) + flow_path_manager.GetUploadsFile("ntfs", "foo"). + Path().AsClientPath()) file_size, _ := upload_metadata_rows[0].GetInt64("file_size") assert.Equal(self.T(), file_size, int64(12)) @@ -470,7 +471,8 @@ func (self *TestSuite) TestClientUploaderStoreFile() { vfs_path, _ = event_rows[0].GetString("VFSPath") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "foo").Path()) + flow_path_manager.GetUploadsFile("ntfs", "foo"). + Path().AsClientPath()) file_size, _ = event_rows[0].GetInt64("Size") assert.Equal(self.T(), file_size, int64(12)) @@ -545,14 +547,15 @@ func (self *TestSuite) TestClientUploaderStoreSparseFile() { // Check the upload metadata file. upload_metadata_rows := test_utils.FileReadRows(self.T(), self.config_obj, - flow_path_manager.UploadMetadata().Path()) + flow_path_manager.UploadMetadata()) // There should be two rows - one for the file and one for the index. assert.Equal(self.T(), len(upload_metadata_rows), 2) vfs_path, _ := upload_metadata_rows[0].GetString("vfs_path") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "sparse").Path()) + flow_path_manager.GetUploadsFile("ntfs", "sparse"). + Path().AsClientPath()) // The file is actually 18 bytes on the client. file_size, _ := upload_metadata_rows[0].GetInt64("file_size") @@ -565,7 +568,8 @@ func (self *TestSuite) TestClientUploaderStoreSparseFile() { // Second row is for the index. vfs_path, _ = upload_metadata_rows[1].GetString("vfs_path") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "sparse").IndexPath()) + flow_path_manager.GetUploadsFile("ntfs", "sparse"). + IndexPath().AsClientPath()) // Check the System.Upload.Completion event. artifact_path_manager, err := artifacts.NewArtifactPathManager( @@ -580,7 +584,8 @@ func (self *TestSuite) TestClientUploaderStoreSparseFile() { vfs_path, _ = event_rows[0].GetString("VFSPath") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "sparse").Path()) + flow_path_manager.GetUploadsFile("ntfs", "sparse"). + Path().AsClientPath()) file_size, _ = event_rows[0].GetInt64("Size") assert.Equal(self.T(), file_size, int64(18)) @@ -660,14 +665,15 @@ func (self *TestSuite) TestClientUploaderStoreSparseFileNTFS() { // Check the upload metadata file. upload_metadata_rows := test_utils.FileReadRows(self.T(), self.config_obj, - flow_path_manager.UploadMetadata().Path()) + flow_path_manager.UploadMetadata()) // There should be two rows - one for the file and one for the index. assert.Equal(self.T(), len(upload_metadata_rows), 2) vfs_path, _ := upload_metadata_rows[0].GetString("vfs_path") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "sparse").Path()) + flow_path_manager.GetUploadsFile("ntfs", "sparse"). + Path().AsClientPath()) // The file is actually 0x100000 bytes on the client. file_size, _ := upload_metadata_rows[0].GetInt64("file_size") @@ -680,7 +686,8 @@ func (self *TestSuite) TestClientUploaderStoreSparseFileNTFS() { // Second row is for the index. vfs_path, _ = upload_metadata_rows[1].GetString("vfs_path") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "sparse").IndexPath()) + flow_path_manager.GetUploadsFile("ntfs", "sparse"). + IndexPath().AsClientPath()) // Check the System.Upload.Completion event. artifact_path_manager, err := artifacts.NewArtifactPathManager( @@ -695,7 +702,8 @@ func (self *TestSuite) TestClientUploaderStoreSparseFileNTFS() { vfs_path, _ = event_rows[0].GetString("VFSPath") assert.Equal(self.T(), vfs_path, - flow_path_manager.GetUploadsFile("ntfs", "sparse").Path()) + flow_path_manager.GetUploadsFile("ntfs", "sparse"). + Path().AsClientPath()) file_size, _ = event_rows[0].GetInt64("Size") assert.Equal(self.T(), file_size, int64(0x100000)) diff --git a/flows/hunts.go b/flows/hunts.go index 5e10c885a1a..c023de07feb 100644 --- a/flows/hunts.go +++ b/flows/hunts.go @@ -308,7 +308,7 @@ func availableHuntDownloadFiles(config_obj *config_proto.Config, hunt_path_manager := paths.NewHuntPathManager(hunt_id) download_file := hunt_path_manager.GetHuntDownloadsFile(false, "") - download_path := path.Dir(download_file) + download_path := download_file.Dir() return getAvailableDownloadFiles(config_obj, download_path) } diff --git a/flows/hunts_test.go b/flows/hunts_test.go index 5b2977d568f..0bb6f5d03d9 100644 --- a/flows/hunts_test.go +++ b/flows/hunts_test.go @@ -100,7 +100,7 @@ sources: assert.NoError(self.T(), err) db := test_utils.GetMemoryDataStore(self.T(), self.config_obj) - hunt_obj, pres := db.Subjects["/hunts/"+hunt_id].(*api_proto.Hunt) + hunt_obj, pres := db.Subjects["/hunts/"+hunt_id+".db"].(*api_proto.Hunt) assert.True(self.T(), pres) assert.Equal(self.T(), hunt_obj.HuntDescription, request.HuntDescription) diff --git a/flows/proto/artifact_collector.pb.go b/flows/proto/artifact_collector.pb.go index 8b52fa0e0cf..c4b7cb18d20 100644 --- a/flows/proto/artifact_collector.pb.go +++ b/flows/proto/artifact_collector.pb.go @@ -382,10 +382,11 @@ type ArtifactUploadedFileInfo struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - VfsPath string `protobuf:"bytes,2,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` - Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` - StoredSize uint64 `protobuf:"varint,4,opt,name=stored_size,json=storedSize,proto3" json:"stored_size,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + VfsPath string `protobuf:"bytes,2,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` + Size uint64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` + StoredSize uint64 `protobuf:"varint,4,opt,name=stored_size,json=storedSize,proto3" json:"stored_size,omitempty"` + Components []string `protobuf:"bytes,5,rep,name=components,proto3" json:"components,omitempty"` } func (x *ArtifactUploadedFileInfo) Reset() { @@ -448,6 +449,13 @@ func (x *ArtifactUploadedFileInfo) GetStoredSize() uint64 { return 0 } +func (x *ArtifactUploadedFileInfo) GetComponents() []string { + if x != nil { + return x.Components + } + return nil +} + // This context is serialized into the data store. type ArtifactCollectorContext struct { state protoimpl.MessageState @@ -945,118 +953,120 @@ var file_artifact_collector_proto_rawDesc = []byte{ 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x7e, 0x0a, 0x18, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, - 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, - 0x19, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, - 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x22, - 0xe3, 0x09, 0x0a, 0x18, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1b, 0x0a, 0x09, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, - 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x12, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x11, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, - 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, - 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, - 0x73, 0x12, 0x41, 0x0a, 0x1d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x70, 0x65, 0x63, - 0x74, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x45, - 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x42, - 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x75, 0x70, - 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x1a, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, - 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, - 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x1c, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6c, 0x6c, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x6f, 0x75, 0x74, 0x73, 0x74, - 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x18, - 0x1f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x6f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6e, 0x65, - 0x78, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x1e, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0e, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x78, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x4f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x37, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x31, 0x12, 0x2f, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x6f, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x9f, 0x01, 0x0a, 0x16, 0x61, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x73, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x42, 0x69, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x63, 0x12, - 0x61, 0x54, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, 0x74, - 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x20, - 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x73, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x6e, 0x61, 0x6d, - 0x65, 0x2e, 0x52, 0x14, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x57, 0x69, 0x74, - 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x0e, 0x75, 0x70, 0x6c, 0x6f, - 0x61, 0x64, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x18, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x69, 0x72, 0x74, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x64, 0x69, 0x72, 0x74, 0x79, 0x12, 0x1f, 0x0a, - 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x18, 0x21, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4c, 0x6f, 0x61, 0x64, 0x73, 0x22, 0x55, - 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x4e, 0x53, 0x45, 0x54, - 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, - 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x12, 0x09, 0x0a, - 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x52, 0x43, 0x48, - 0x49, 0x56, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, - 0x4c, 0x45, 0x44, 0x10, 0x05, 0x22, 0x5f, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x3a, 0x0a, 0x09, 0x61, 0x72, - 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, - 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x61, 0x72, 0x74, - 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0x9f, 0x01, 0x0a, 0x10, 0x43, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, - 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0b, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x55, 0x0a, 0x10, 0x55, 0x70, 0x6c, 0x6f, + 0x9e, 0x01, 0x0a, 0x18, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, - 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x42, - 0x33, 0x5a, 0x31, 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, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, + 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x73, + 0x22, 0xe3, 0x09, 0x0a, 0x18, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, + 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x12, 0x1b, 0x0a, + 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x72, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x63, 0x6b, 0x74, 0x72, 0x61, 0x63, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x12, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, + 0x1f, 0x0a, 0x0b, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x54, 0x69, 0x6d, 0x65, + 0x12, 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, + 0x65, 0x73, 0x12, 0x41, 0x0a, 0x1d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x78, 0x70, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x45, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, + 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x75, + 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x1a, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, + 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x30, 0x0a, 0x14, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, + 0x1c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x12, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x6c, 0x6c, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x20, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x31, 0x0a, 0x14, 0x6f, 0x75, 0x74, 0x73, + 0x74, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, + 0x18, 0x1f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x6f, 0x75, 0x74, 0x73, 0x74, 0x61, 0x6e, 0x64, + 0x69, 0x6e, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x12, 0x28, 0x0a, 0x10, 0x6e, + 0x65, 0x78, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x69, 0x64, 0x18, + 0x1e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x12, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1d, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x11, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x75, 0x72, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x0e, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x43, 0x6f, 0x6e, + 0x74, 0x65, 0x78, 0x74, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x4f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x37, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x31, 0x12, 0x2f, 0x43, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x20, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x73, 0x65, 0x6e, 0x74, 0x20, 0x62, 0x79, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x6f, 0x74, 0x69, 0x66, + 0x69, 0x65, 0x64, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x4e, + 0x6f, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x9f, 0x01, 0x0a, 0x16, 0x61, 0x72, 0x74, 0x69, + 0x66, 0x61, 0x63, 0x74, 0x73, 0x5f, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x73, 0x18, 0x16, 0x20, 0x03, 0x28, 0x09, 0x42, 0x69, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x63, + 0x12, 0x61, 0x54, 0x68, 0x65, 0x20, 0x66, 0x75, 0x6c, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x68, 0x20, + 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, + 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x61, 0x6b, 0x65, 0x73, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x2f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x6e, 0x61, + 0x6d, 0x65, 0x2e, 0x52, 0x14, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x57, 0x69, + 0x74, 0x68, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x46, 0x0a, 0x0e, 0x75, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x18, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x0d, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, + 0x73, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x14, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4c, 0x6f, 0x67, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x69, 0x72, 0x74, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x64, 0x69, 0x72, 0x74, 0x79, 0x12, 0x1f, + 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x73, 0x18, 0x21, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4c, 0x6f, 0x61, 0x64, 0x73, 0x22, + 0x55, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x4e, 0x53, 0x45, + 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, + 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x49, 0x4e, 0x49, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x12, 0x09, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x52, 0x43, + 0x48, 0x49, 0x56, 0x45, 0x44, 0x10, 0x04, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x41, 0x4e, 0x43, 0x45, + 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x22, 0x5f, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x3a, 0x0a, 0x09, 0x61, + 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, + 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0x9f, 0x01, 0x0a, 0x10, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x6f, 0x72, 0x41, 0x72, 0x67, 0x73, 0x52, 0x09, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x5f, 0x65, 0x76, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x0b, 0x6c, 0x61, + 0x62, 0x65, 0x6c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x55, 0x0a, 0x10, 0x55, 0x70, 0x6c, + 0x6f, 0x61, 0x64, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, + 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, + 0x42, 0x33, 0x5a, 0x31, 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, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/flows/proto/artifact_collector.proto b/flows/proto/artifact_collector.proto index aabbf1567c1..b7842d9494c 100644 --- a/flows/proto/artifact_collector.proto +++ b/flows/proto/artifact_collector.proto @@ -82,6 +82,7 @@ message ArtifactUploadedFileInfo { string vfs_path = 2; uint64 size = 3; uint64 stored_size = 4; + repeated string components = 5; } // This context is serialized into the data store. diff --git a/flows/proto/vfs.pb.go b/flows/proto/vfs.pb.go index a185b8bc246..b9d3bd7ef46 100644 --- a/flows/proto/vfs.pb.go +++ b/flows/proto/vfs.pb.go @@ -11,7 +11,6 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" - proto "www.velocidex.com/golang/velociraptor/actions/proto" _ "www.velocidex.com/golang/velociraptor/proto" ) @@ -22,17 +21,23 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// This is stored in the VFS datastores to indicate where the actual +// download exist (usually in the flow filestore). type VFSDownloadInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Deprecated but leave it here so we can read older files + // downloaded within the filestore. VfsPath string `protobuf:"bytes,1,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` Size uint64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` Mtime uint64 `protobuf:"varint,3,opt,name=mtime,proto3" json:"mtime,omitempty"` Sparse bool `protobuf:"varint,4,opt,name=sparse,proto3" json:"sparse,omitempty"` MD5 string `protobuf:"bytes,5,opt,name=MD5,proto3" json:"MD5,omitempty"` SHA256 string `protobuf:"bytes,6,opt,name=SHA256,proto3" json:"SHA256,omitempty"` + // The VFS path is now expressed as a list of components + Components []string `protobuf:"bytes,7,rep,name=components,proto3" json:"components,omitempty"` } func (x *VFSDownloadInfo) Reset() { @@ -109,350 +114,9 @@ func (x *VFSDownloadInfo) GetSHA256() string { return "" } -type VFSListResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Response string `protobuf:"bytes,1,opt,name=Response,proto3" json:"Response,omitempty"` - Columns []string `protobuf:"bytes,2,rep,name=Columns,proto3" json:"Columns,omitempty"` - Query *proto.VQLRequest `protobuf:"bytes,3,opt,name=Query,proto3" json:"Query,omitempty"` - Timestamp uint64 `protobuf:"varint,4,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - TotalRows uint64 `protobuf:"varint,7,opt,name=total_rows,json=totalRows,proto3" json:"total_rows,omitempty"` - Types []*proto.VQLTypeMap `protobuf:"bytes,8,rep,name=types,proto3" json:"types,omitempty"` - // The actual artifact that contains the data. - ClientId string `protobuf:"bytes,9,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - FlowId string `protobuf:"bytes,10,opt,name=flow_id,json=flowId,proto3" json:"flow_id,omitempty"` -} - -func (x *VFSListResponse) Reset() { - *x = VFSListResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_vfs_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VFSListResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VFSListResponse) ProtoMessage() {} - -func (x *VFSListResponse) ProtoReflect() protoreflect.Message { - mi := &file_vfs_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VFSListResponse.ProtoReflect.Descriptor instead. -func (*VFSListResponse) Descriptor() ([]byte, []int) { - return file_vfs_proto_rawDescGZIP(), []int{1} -} - -func (x *VFSListResponse) GetResponse() string { +func (x *VFSDownloadInfo) GetComponents() []string { if x != nil { - return x.Response - } - return "" -} - -func (x *VFSListResponse) GetColumns() []string { - if x != nil { - return x.Columns - } - return nil -} - -func (x *VFSListResponse) GetQuery() *proto.VQLRequest { - if x != nil { - return x.Query - } - return nil -} - -func (x *VFSListResponse) GetTimestamp() uint64 { - if x != nil { - return x.Timestamp - } - return 0 -} - -func (x *VFSListResponse) GetTotalRows() uint64 { - if x != nil { - return x.TotalRows - } - return 0 -} - -func (x *VFSListResponse) GetTypes() []*proto.VQLTypeMap { - if x != nil { - return x.Types - } - return nil -} - -func (x *VFSListResponse) GetClientId() string { - if x != nil { - return x.ClientId - } - return "" -} - -func (x *VFSListResponse) GetFlowId() string { - if x != nil { - return x.FlowId - } - return "" -} - -type VFSStatDownloadRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - Accessor string `protobuf:"bytes,4,opt,name=accessor,proto3" json:"accessor,omitempty"` - Path string `protobuf:"bytes,5,opt,name=path,proto3" json:"path,omitempty"` -} - -func (x *VFSStatDownloadRequest) Reset() { - *x = VFSStatDownloadRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vfs_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VFSStatDownloadRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VFSStatDownloadRequest) ProtoMessage() {} - -func (x *VFSStatDownloadRequest) ProtoReflect() protoreflect.Message { - mi := &file_vfs_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VFSStatDownloadRequest.ProtoReflect.Descriptor instead. -func (*VFSStatDownloadRequest) Descriptor() ([]byte, []int) { - return file_vfs_proto_rawDescGZIP(), []int{2} -} - -func (x *VFSStatDownloadRequest) GetClientId() string { - if x != nil { - return x.ClientId - } - return "" -} - -func (x *VFSStatDownloadRequest) GetAccessor() string { - if x != nil { - return x.Accessor - } - return "" -} - -func (x *VFSStatDownloadRequest) GetPath() string { - if x != nil { - return x.Path - } - return "" -} - -type VFSListRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - VfsPath string `protobuf:"bytes,2,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` - RecursionDepth uint64 `protobuf:"varint,3,opt,name=recursion_depth,json=recursionDepth,proto3" json:"recursion_depth,omitempty"` -} - -func (x *VFSListRequest) Reset() { - *x = VFSListRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vfs_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VFSListRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VFSListRequest) ProtoMessage() {} - -func (x *VFSListRequest) ProtoReflect() protoreflect.Message { - mi := &file_vfs_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VFSListRequest.ProtoReflect.Descriptor instead. -func (*VFSListRequest) Descriptor() ([]byte, []int) { - return file_vfs_proto_rawDescGZIP(), []int{3} -} - -func (x *VFSListRequest) GetClientId() string { - if x != nil { - return x.ClientId - } - return "" -} - -func (x *VFSListRequest) GetVfsPath() string { - if x != nil { - return x.VfsPath - } - return "" -} - -func (x *VFSListRequest) GetRecursionDepth() uint64 { - if x != nil { - return x.RecursionDepth - } - return 0 -} - -type VFSListRequestState struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - VfsPath string `protobuf:"bytes,1,opt,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` - Accessor string `protobuf:"bytes,3,opt,name=accessor,proto3" json:"accessor,omitempty"` - Current *proto.VQLResponse `protobuf:"bytes,2,opt,name=current,proto3" json:"current,omitempty"` -} - -func (x *VFSListRequestState) Reset() { - *x = VFSListRequestState{} - if protoimpl.UnsafeEnabled { - mi := &file_vfs_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VFSListRequestState) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VFSListRequestState) ProtoMessage() {} - -func (x *VFSListRequestState) ProtoReflect() protoreflect.Message { - mi := &file_vfs_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VFSListRequestState.ProtoReflect.Descriptor instead. -func (*VFSListRequestState) Descriptor() ([]byte, []int) { - return file_vfs_proto_rawDescGZIP(), []int{4} -} - -func (x *VFSListRequestState) GetVfsPath() string { - if x != nil { - return x.VfsPath - } - return "" -} - -func (x *VFSListRequestState) GetAccessor() string { - if x != nil { - return x.Accessor - } - return "" -} - -func (x *VFSListRequestState) GetCurrent() *proto.VQLResponse { - if x != nil { - return x.Current - } - return nil -} - -type VFSDownloadFileRequest struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - VfsPath []string `protobuf:"bytes,2,rep,name=vfs_path,json=vfsPath,proto3" json:"vfs_path,omitempty"` -} - -func (x *VFSDownloadFileRequest) Reset() { - *x = VFSDownloadFileRequest{} - if protoimpl.UnsafeEnabled { - mi := &file_vfs_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *VFSDownloadFileRequest) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*VFSDownloadFileRequest) ProtoMessage() {} - -func (x *VFSDownloadFileRequest) ProtoReflect() protoreflect.Message { - mi := &file_vfs_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use VFSDownloadFileRequest.ProtoReflect.Descriptor instead. -func (*VFSDownloadFileRequest) Descriptor() ([]byte, []int) { - return file_vfs_proto_rawDescGZIP(), []int{5} -} - -func (x *VFSDownloadFileRequest) GetClientId() string { - if x != nil { - return x.ClientId - } - return "" -} - -func (x *VFSDownloadFileRequest) GetVfsPath() []string { - if x != nil { - return x.VfsPath + return x.Components } return nil } @@ -469,7 +133,7 @@ type ClientMonitoringState struct { func (x *ClientMonitoringState) Reset() { *x = ClientMonitoringState{} if protoimpl.UnsafeEnabled { - mi := &file_vfs_proto_msgTypes[6] + mi := &file_vfs_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -482,7 +146,7 @@ func (x *ClientMonitoringState) String() string { func (*ClientMonitoringState) ProtoMessage() {} func (x *ClientMonitoringState) ProtoReflect() protoreflect.Message { - mi := &file_vfs_proto_msgTypes[6] + mi := &file_vfs_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -495,7 +159,7 @@ func (x *ClientMonitoringState) ProtoReflect() protoreflect.Message { // Deprecated: Use ClientMonitoringState.ProtoReflect.Descriptor instead. func (*ClientMonitoringState) Descriptor() ([]byte, []int) { - return file_vfs_proto_rawDescGZIP(), []int{6} + return file_vfs_proto_rawDescGZIP(), []int{1} } func (x *ClientMonitoringState) GetVersion() uint64 { @@ -517,91 +181,34 @@ var File_vfs_proto protoreflect.FileDescriptor var file_vfs_proto_rawDesc = []byte{ 0x0a, 0x09, 0x76, 0x66, 0x73, 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, 0x1a, 0x17, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x71, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x98, 0x01, 0x0a, 0x0f, 0x56, 0x46, 0x53, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, - 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, - 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, - 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, - 0x73, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x70, - 0x61, 0x72, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x73, 0x70, 0x61, 0x72, - 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x44, 0x35, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x4d, 0x44, 0x35, 0x12, 0x16, 0x0a, 0x06, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x22, 0x8c, 0x02, 0x0a, - 0x0f, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, - 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x43, - 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x73, 0x12, 0x27, 0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, - 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1d, 0x0a, - 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x77, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x09, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x6f, 0x77, 0x73, 0x12, 0x27, 0x0a, 0x05, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x54, 0x79, 0x70, 0x65, 0x4d, 0x61, 0x70, 0x52, 0x05, - 0x74, 0x79, 0x70, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64, 0x22, 0x65, 0x0a, 0x16, 0x56, - 0x46, 0x53, 0x53, 0x74, 0x61, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, - 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x12, - 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, - 0x74, 0x68, 0x22, 0xf8, 0x01, 0x0a, 0x0e, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x42, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x25, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1f, - 0x0a, 0x06, 0x52, 0x44, 0x46, 0x55, 0x52, 0x4e, 0x12, 0x12, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6c, - 0x69, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x1a, 0x01, 0x02, 0x52, - 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x42, 0x0a, 0x08, 0x76, 0x66, 0x73, - 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x27, 0xe2, 0xfc, 0xe3, - 0xc4, 0x01, 0x21, 0x12, 0x1f, 0x54, 0x68, 0x65, 0x20, 0x56, 0x46, 0x53, 0x20, 0x50, 0x61, 0x74, - 0x68, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x20, - 0x69, 0x6e, 0x20, 0x2e, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x5e, 0x0a, - 0x0f, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x65, 0x70, 0x74, 0x68, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x35, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2a, - 0x49, 0x66, 0x20, 0x3e, 0x20, 0x30, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x63, 0x75, - 0x72, 0x73, 0x65, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6d, 0x61, 0x6e, 0x79, 0x20, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x32, 0x01, 0x30, 0x52, 0x0e, 0x72, - 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x70, 0x74, 0x68, 0x22, 0x7a, 0x0a, - 0x13, 0x56, 0x46, 0x53, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, - 0x1a, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x07, 0x63, - 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x52, 0x07, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x16, 0x56, 0x46, - 0x53, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x20, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x1a, 0x0a, - 0x06, 0x52, 0x44, 0x46, 0x55, 0x52, 0x4e, 0x12, 0x0d, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, - 0x65, 0x6e, 0x74, 0x20, 0x69, 0x64, 0x1a, 0x01, 0x02, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x49, 0x64, 0x12, 0x48, 0x0a, 0x08, 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x42, 0x2d, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x27, 0x12, 0x25, 0x54, - 0x68, 0x65, 0x20, 0x56, 0x46, 0x53, 0x20, 0x50, 0x61, 0x74, 0x68, 0x20, 0x74, 0x6f, 0x20, 0x74, - 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x64, 0x6f, 0x77, 0x6e, 0x6c, - 0x6f, 0x61, 0x64, 0x2e, 0x52, 0x07, 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x22, 0xbb, 0x01, - 0x0a, 0x15, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, - 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x40, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, - 0x12, 0x1e, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x27, 0x73, 0x20, 0x72, - 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, - 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x60, 0x0a, 0x15, 0x6c, 0x61, 0x73, - 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x2c, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x26, - 0x12, 0x24, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, - 0x77, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, - 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x13, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x33, 0x5a, 0x31, 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, 0x66, 0x6c, 0x6f, 0x77, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb8, 0x01, 0x0a, 0x0f, 0x56, 0x46, 0x53, + 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x19, 0x0a, 0x08, + 0x76, 0x66, 0x73, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x76, 0x66, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x06, 0x73, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x4d, 0x44, 0x35, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4d, 0x44, 0x35, 0x12, 0x16, 0x0a, 0x06, 0x53, + 0x48, 0x41, 0x32, 0x35, 0x36, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x53, 0x48, 0x41, + 0x32, 0x35, 0x36, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, + 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, + 0x6e, 0x74, 0x73, 0x22, 0xbb, 0x01, 0x0a, 0x15, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x4d, 0x6f, + 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x40, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x42, 0x26, + 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x54, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x27, 0x73, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x20, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x60, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x2c, + 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x26, 0x12, 0x24, 0x54, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x73, 0x74, + 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x77, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x52, 0x13, 0x6c, 0x61, + 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x42, 0x33, 0x5a, 0x31, 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, 0x66, 0x6c, 0x6f, 0x77, 0x73, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -616,28 +223,17 @@ func file_vfs_proto_rawDescGZIP() []byte { return file_vfs_proto_rawDescData } -var file_vfs_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_vfs_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_vfs_proto_goTypes = []interface{}{ - (*VFSDownloadInfo)(nil), // 0: proto.VFSDownloadInfo - (*VFSListResponse)(nil), // 1: proto.VFSListResponse - (*VFSStatDownloadRequest)(nil), // 2: proto.VFSStatDownloadRequest - (*VFSListRequest)(nil), // 3: proto.VFSListRequest - (*VFSListRequestState)(nil), // 4: proto.VFSListRequestState - (*VFSDownloadFileRequest)(nil), // 5: proto.VFSDownloadFileRequest - (*ClientMonitoringState)(nil), // 6: proto.ClientMonitoringState - (*proto.VQLRequest)(nil), // 7: proto.VQLRequest - (*proto.VQLTypeMap)(nil), // 8: proto.VQLTypeMap - (*proto.VQLResponse)(nil), // 9: proto.VQLResponse + (*VFSDownloadInfo)(nil), // 0: proto.VFSDownloadInfo + (*ClientMonitoringState)(nil), // 1: proto.ClientMonitoringState } var file_vfs_proto_depIdxs = []int32{ - 7, // 0: proto.VFSListResponse.Query:type_name -> proto.VQLRequest - 8, // 1: proto.VFSListResponse.types:type_name -> proto.VQLTypeMap - 9, // 2: proto.VFSListRequestState.current:type_name -> proto.VQLResponse - 3, // [3:3] is the sub-list for method output_type - 3, // [3:3] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_vfs_proto_init() } @@ -659,66 +255,6 @@ func file_vfs_proto_init() { } } file_vfs_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VFSListResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vfs_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VFSStatDownloadRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vfs_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VFSListRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vfs_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VFSListRequestState); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vfs_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*VFSDownloadFileRequest); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_vfs_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ClientMonitoringState); i { case 0: return &v.state @@ -737,7 +273,7 @@ func file_vfs_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_vfs_proto_rawDesc, NumEnums: 0, - NumMessages: 7, + NumMessages: 2, NumExtensions: 0, NumServices: 0, }, diff --git a/flows/proto/vfs.proto b/flows/proto/vfs.proto index 07470f915be..716543111b5 100644 --- a/flows/proto/vfs.proto +++ b/flows/proto/vfs.proto @@ -1,73 +1,26 @@ syntax = "proto3"; import "proto/semantic.proto"; -import "actions/proto/vql.proto"; package proto; option go_package = "www.velocidex.com/golang/velociraptor/flows/proto"; +// This is stored in the VFS datastores to indicate where the actual +// download exist (usually in the flow filestore). message VFSDownloadInfo { + // Deprecated but leave it here so we can read older files + // downloaded within the filestore. string vfs_path = 1; + uint64 size = 2; uint64 mtime = 3; bool sparse = 4; string MD5 = 5; string SHA256 = 6; -} - -message VFSListResponse { - string Response = 1; - repeated string Columns = 2; - VQLRequest Query = 3; - uint64 timestamp = 4; - uint64 total_rows = 7; - repeated VQLTypeMap types = 8; - - // The actual artifact that contains the data. - string client_id = 9; - string flow_id = 10; -} - -message VFSStatDownloadRequest { - string client_id = 1; - string accessor = 4; - string path = 5; -} - -message VFSListRequest { - string client_id = 1 [(sem_type) = { - description: "The client to list", - type: "RDFURN", - label: HIDDEN, - }]; - - string vfs_path = 2 [(sem_type) = { - description: "The VFS Path to list files in .", - }]; - - uint64 recursion_depth = 3 [(sem_type) = { - default: "0", - description: "If > 0 then recurse this many directories.", - }]; -} - -message VFSListRequestState { - string vfs_path = 1; - string accessor = 3; - VQLResponse current = 2; -} -message VFSDownloadFileRequest { - string client_id = 1 [(sem_type) = { - description: "The client id", - type: "RDFURN", - label: HIDDEN, - }]; - - repeated string vfs_path = 2 [(sem_type) = { - description: "The VFS Path to the file to download.", - }]; + // The VFS path is now expressed as a list of components + repeated string components = 7; } message ClientMonitoringState { diff --git a/gui/velociraptor/src/components/clients/client-summary.js b/gui/velociraptor/src/components/clients/client-summary.js index a599e73fc47..8cb2642c812 100644 --- a/gui/velociraptor/src/components/clients/client-summary.js +++ b/gui/velociraptor/src/components/clients/client-summary.js @@ -42,7 +42,7 @@ export default class VeloClientSummary extends Component { }).catch(err=>{ // The client is not valid - navigate away from // it. - this.props.setClient({}); + // this.props.setClient({}); return false; }); } diff --git a/gui/velociraptor/src/components/clients/host-info.js b/gui/velociraptor/src/components/clients/host-info.js index 109e156373d..a9ef038b02b 100644 --- a/gui/velociraptor/src/components/clients/host-info.js +++ b/gui/velociraptor/src/components/clients/host-info.js @@ -41,6 +41,14 @@ class QuarantineDialog extends Component { message: "", } + componentDidMount = () => { + this.source = axios.CancelToken.source(); + } + + componentWillUnmount() { + this.source.cancel(); + } + startQuarantine = () => { let client_id = this.props.client && this.props.client.client_id; @@ -61,7 +69,7 @@ class QuarantineDialog extends Component { ()=>{ this.props.onClose(); this.setState({loading: false}); - }); + }, this.source.token); }); } } @@ -246,7 +254,7 @@ class VeloHostInfo extends Component { ()=>{ this.updateClientInfo(); this.setState({loading: false}); - }); + }, this.source.token); }); } } diff --git a/gui/velociraptor/src/components/flows/flows-list.js b/gui/velociraptor/src/components/flows/flows-list.js index 7a7883b31a3..c0b9fb772e8 100644 --- a/gui/velociraptor/src/components/flows/flows-list.js +++ b/gui/velociraptor/src/components/flows/flows-list.js @@ -28,6 +28,9 @@ import { withRouter } from "react-router-dom"; import { runArtifact } from "./utils.js"; import Modal from 'react-bootstrap/Modal'; +import UserConfig from '../core/user.js'; +import VeloForm from '../forms/form.js'; + import axios from 'axios'; @@ -42,6 +45,14 @@ export class DeleteFlowDialog extends React.PureComponent { loading: false, } + componentDidMount = () => { + this.source = axios.CancelToken.source(); + } + + componentWillUnmount() { + this.source.cancel(); + } + startDeleteFlow = () => { let client_id = this.props.client && this.props.client.client_id; let flow_id = this.props.flow && this.props.flow.session_id; @@ -55,7 +66,7 @@ export class DeleteFlowDialog extends React.PureComponent { ReallyDoIt: "Y"}, ()=>{ this.props.onClose(); this.setState({loading: false}); - }); + }, this.source.token); } } @@ -92,6 +103,88 @@ export class DeleteFlowDialog extends React.PureComponent { } } +export class SaveCollectionDialog extends React.PureComponent { + static contextType = UserConfig; + static propTypes = { + client: PropTypes.object, + flow: PropTypes.object, + onClose: PropTypes.func.isRequired, + } + + state = { + loading: false, + } + + componentDidMount = () => { + this.source = axios.CancelToken.source(); + } + + componentWillUnmount() { + this.source.cancel(); + } + + startSaveFlow = () => { + let client_id = this.props.client && this.props.client.client_id; + let specs = this.props.flow.request.specs; + let type = "CLIENT"; + if (client_id==="server") { + type = "SERVER"; + } + + this.setState({loading: true}); + runArtifact("server", // This collection happens on the server. + "Server.Utils.SaveFavoriteFlow", + { + Specs: JSON.stringify(specs), + Name: this.state.name, + Description: this.state.description, + Type: type, + }, ()=>{ + this.props.onClose(); + this.setState({loading: false}); + }, this.source.token); + } + + render() { + let collected_artifacts = this.props.flow.artifacts_with_results || []; + let artifacts = collected_artifacts.join(","); + return ( + + + Save this collection to your Favorites + + + You can easily collect the same collection from your + favorites in future. +
+ This collection was the artifacts {artifacts} +

+ this.setState({name:x})} + /> + this.setState({description:x})} + /> + +
+ + + + +
+ ); + } +} + class FlowsList extends React.Component { static propTypes = { client: PropTypes.object, @@ -291,6 +384,13 @@ class FlowsList extends React.Component { this.props.fetchFlows(); }}/> } + { this.state.showSaveCollectionDialog && + { + this.setState({showSaveCollectionDialog: false}); + }}/> + } { this.state.showWizard && + { isServer &&