mirror of
https://github.com/Velocidex/velociraptor.git
synced 2026-10-12 02:09:59 +00:00
Added a watch_json() plugin (#3298)
This is based on the watch_syslog() plugin. Also added tests and bugfixes to watch_syslog() Also suppress detailed errors to non-API HTTP requests like the public directory handler.
This commit is contained in:
@@ -10,29 +10,9 @@ import (
|
||||
"www.velocidex.com/golang/velociraptor/constants"
|
||||
"www.velocidex.com/golang/velociraptor/json"
|
||||
"www.velocidex.com/golang/velociraptor/logging"
|
||||
http_utils "www.velocidex.com/golang/velociraptor/utils/http"
|
||||
)
|
||||
|
||||
// Record the status of the request so we can log it.
|
||||
type statusRecorder struct {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
status int
|
||||
error []byte
|
||||
}
|
||||
|
||||
func (self *statusRecorder) WriteHeader(code int) {
|
||||
self.status = code
|
||||
self.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (self *statusRecorder) Write(buf []byte) (int, error) {
|
||||
if self.status == 500 {
|
||||
self.error = buf
|
||||
}
|
||||
|
||||
return self.ResponseWriter.Write(buf)
|
||||
}
|
||||
|
||||
func GetUserInfo(ctx context.Context,
|
||||
config_obj *config_proto.Config) *api_proto.VelociraptorUser {
|
||||
result := &api_proto.VelociraptorUser{}
|
||||
@@ -51,22 +31,23 @@ func GetUserInfo(ctx context.Context,
|
||||
|
||||
func GetLoggingHandler(config_obj *config_proto.Config) func(http.Handler) http.Handler {
|
||||
logger := logging.GetLogger(config_obj, &logging.GUIComponent)
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rec := &statusRecorder{
|
||||
rec := &http_utils.StatusRecorder{
|
||||
w,
|
||||
w.(http.Flusher),
|
||||
200, nil}
|
||||
defer func() {
|
||||
if rec.status == 500 {
|
||||
if rec.Status == 500 {
|
||||
logger.WithFields(
|
||||
logrus.Fields{
|
||||
"method": r.Method,
|
||||
"url": r.URL.Path,
|
||||
"remote": r.RemoteAddr,
|
||||
"error": string(rec.error),
|
||||
"error": string(rec.Error),
|
||||
"user-agent": r.UserAgent(),
|
||||
"status": rec.status,
|
||||
"status": rec.Status,
|
||||
"user": GetUserInfo(
|
||||
r.Context(), config_obj).Name,
|
||||
}).Error("")
|
||||
@@ -78,7 +59,7 @@ func GetLoggingHandler(config_obj *config_proto.Config) func(http.Handler) http.
|
||||
"url": r.URL.Path,
|
||||
"remote": r.RemoteAddr,
|
||||
"user-agent": r.UserAgent(),
|
||||
"status": rec.status,
|
||||
"status": rec.Status,
|
||||
"user": GetUserInfo(
|
||||
r.Context(), config_obj).Name,
|
||||
}).Info("")
|
||||
|
||||
+6
-26
@@ -27,29 +27,9 @@ import (
|
||||
"www.velocidex.com/golang/velociraptor/constants"
|
||||
"www.velocidex.com/golang/velociraptor/json"
|
||||
"www.velocidex.com/golang/velociraptor/logging"
|
||||
http_utils "www.velocidex.com/golang/velociraptor/utils/http"
|
||||
)
|
||||
|
||||
// Record the status of the request so we can log it.
|
||||
type statusRecorder struct {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
status int
|
||||
error []byte
|
||||
}
|
||||
|
||||
func (self *statusRecorder) WriteHeader(code int) {
|
||||
self.status = code
|
||||
self.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (self *statusRecorder) Write(buf []byte) (int, error) {
|
||||
if self.status == 500 {
|
||||
self.error = buf
|
||||
}
|
||||
|
||||
return self.ResponseWriter.Write(buf)
|
||||
}
|
||||
|
||||
func GetUserInfo(ctx context.Context,
|
||||
config_obj *config_proto.Config) *api_proto.VelociraptorUser {
|
||||
result := &api_proto.VelociraptorUser{}
|
||||
@@ -70,20 +50,20 @@ func GetLoggingHandler(config_obj *config_proto.Config) func(http.Handler) http.
|
||||
logger := logging.GetLogger(config_obj, &logging.GUIComponent)
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rec := &statusRecorder{
|
||||
rec := &http_utils.StatusRecorder{
|
||||
w,
|
||||
w.(http.Flusher),
|
||||
200, nil}
|
||||
defer func() {
|
||||
if rec.status == 500 {
|
||||
if rec.Status == 500 {
|
||||
logger.WithFields(
|
||||
logrus.Fields{
|
||||
"method": r.Method,
|
||||
"url": r.URL.Path,
|
||||
"remote": r.RemoteAddr,
|
||||
"error": string(rec.error),
|
||||
"error": string(rec.Error),
|
||||
"user-agent": r.UserAgent(),
|
||||
"status": rec.status,
|
||||
"status": rec.Status,
|
||||
"user": GetUserInfo(
|
||||
r.Context(), config_obj).Name,
|
||||
}).Error("")
|
||||
@@ -95,7 +75,7 @@ func GetLoggingHandler(config_obj *config_proto.Config) func(http.Handler) http.
|
||||
"url": r.URL.Path,
|
||||
"remote": r.RemoteAddr,
|
||||
"user-agent": r.UserAgent(),
|
||||
"status": rec.status,
|
||||
"status": rec.Status,
|
||||
"user": GetUserInfo(
|
||||
r.Context(), config_obj).Name,
|
||||
}).Info("")
|
||||
|
||||
@@ -309,6 +309,8 @@ func handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func initDebugServer(config_obj *config_proto.Config) error {
|
||||
if *debug_flag {
|
||||
config_obj.DebugMode = true
|
||||
|
||||
logger := logging.GetLogger(config_obj, &logging.FrontendComponent)
|
||||
logger.Info("<green>Starting</> debug server on <cyan>http://127.0.0.1:%v/debug/pprof", *debug_flag_port)
|
||||
|
||||
|
||||
+213
-176
@@ -3499,9 +3499,15 @@ type Defaults struct {
|
||||
// Normally the inventory service attempts to download tools in
|
||||
// its own but if this is set, we prevent any external access.
|
||||
DisableInventoryServiceExternalAccess bool `protobuf:"varint,34,opt,name=disable_inventory_service_external_access,json=disableInventoryServiceExternalAccess,proto3" json:"disable_inventory_service_external_access,omitempty"`
|
||||
// Controls how exports work (creating hunt or colletion exports to a zip file).
|
||||
// Controls how exports work (creating hunt or colletion exports
|
||||
// to a zip file).
|
||||
ExportConcurrency int64 `protobuf:"varint,40,opt,name=export_concurrency,json=exportConcurrency,proto3" json:"export_concurrency,omitempty"`
|
||||
ExportMaxTimeoutSec int64 `protobuf:"varint,41,opt,name=export_max_timeout_sec,json=exportMaxTimeoutSec,proto3" json:"export_max_timeout_sec,omitempty"`
|
||||
// Watch plugin frequency sleep time in seconds: How often
|
||||
// watch_syslog() will check for changes (default 3).
|
||||
WatchPluginFrequency int64 `protobuf:"varint,44,opt,name=watch_plugin_frequency,json=watchPluginFrequency,proto3" json:"watch_plugin_frequency,omitempty"`
|
||||
// Maximum length of the line that will be parsed (16kb)
|
||||
WatchPluginBufferSize int64 `protobuf:"varint,45,opt,name=watch_plugin_buffer_size,json=watchPluginBufferSize,proto3" json:"watch_plugin_buffer_size,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Defaults) Reset() {
|
||||
@@ -3767,6 +3773,20 @@ func (x *Defaults) GetExportMaxTimeoutSec() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Defaults) GetWatchPluginFrequency() int64 {
|
||||
if x != nil {
|
||||
return x.WatchPluginFrequency
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *Defaults) GetWatchPluginBufferSize() int64 {
|
||||
if x != nil {
|
||||
return x.WatchPluginBufferSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Configures crypto preferences
|
||||
type CryptoConfig struct {
|
||||
state protoimpl.MessageState
|
||||
@@ -4141,8 +4161,9 @@ type Config struct {
|
||||
// internally that mark each org's config object. They should
|
||||
// definitely not be set on the client's config because the client
|
||||
// does not know or use its own org id.
|
||||
OrgId string `protobuf:"bytes,36,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
|
||||
OrgName string `protobuf:"bytes,37,opt,name=org_name,json=orgName,proto3" json:"org_name,omitempty"`
|
||||
OrgId string `protobuf:"bytes,36,opt,name=org_id,json=orgId,proto3" json:"org_id,omitempty"`
|
||||
OrgName string `protobuf:"bytes,37,opt,name=org_name,json=orgName,proto3" json:"org_name,omitempty"`
|
||||
DebugMode bool `protobuf:"varint,41,opt,name=debug_mode,json=debugMode,proto3" json:"debug_mode,omitempty"`
|
||||
// The services that will run at initialization. Note this is not
|
||||
// set in the config file by the user but is propagated from the
|
||||
// startup code.
|
||||
@@ -4365,6 +4386,13 @@ func (x *Config) GetOrgName() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Config) GetDebugMode() bool {
|
||||
if x != nil {
|
||||
return x.DebugMode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *Config) GetServices() *ServerServicesConfig {
|
||||
if x != nil {
|
||||
return x.Services
|
||||
@@ -5517,7 +5545,7 @@ var file_config_proto_rawDesc = []byte{
|
||||
0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x2c, 0x0a, 0x12, 0x63,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45,
|
||||
0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x83, 0x0e, 0x0a, 0x08, 0x44, 0x65,
|
||||
0x76, 0x65, 0x6e, 0x74, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0xf2, 0x0e, 0x0a, 0x08, 0x44, 0x65,
|
||||
0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x68, 0x75, 0x6e, 0x74, 0x5f, 0x65,
|
||||
0x78, 0x70, 0x69, 0x72, 0x79, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0f, 0x68, 0x75, 0x6e, 0x74, 0x45, 0x78, 0x70, 0x69, 0x72, 0x79, 0x48, 0x6f, 0x75,
|
||||
@@ -5629,179 +5657,188 @@ var file_config_proto_rawDesc = []byte{
|
||||
0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x33, 0x0a, 0x16, 0x65, 0x78,
|
||||
0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
|
||||
0x5f, 0x73, 0x65, 0x63, 0x18, 0x29, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x65, 0x78, 0x70, 0x6f,
|
||||
0x72, 0x74, 0x4d, 0x61, 0x78, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x22,
|
||||
0xad, 0x04, 0x0a, 0x0c, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x73, 0x12,
|
||||
0x7f, 0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74,
|
||||
0x68, 0x75, 0x6d, 0x62, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
||||
0x42, 0x46, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x40, 0x12, 0x3e, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36,
|
||||
0x20, 0x74, 0x68, 0x75, 0x6d, 0x62, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20,
|
||||
0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61,
|
||||
0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x6c,
|
||||
0x6c, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73,
|
||||
0x12, 0xd5, 0x01, 0x0a, 0x1d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||
0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f,
|
||||
0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x90, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01,
|
||||
0x89, 0x01, 0x12, 0x86, 0x01, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65,
|
||||
0x20, 0x77, 0x61, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x56, 0x65,
|
||||
0x6c, 0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x20, 0x76, 0x65, 0x72, 0x69, 0x66,
|
||||
0x69, 0x65, 0x73, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x73, 0x3a, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x28, 0x74, 0x68, 0x65, 0x20, 0x64,
|
||||
0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x29, 0x2c, 0x20, 0x50, 0x4b, 0x49, 0x5f, 0x4f, 0x52, 0x5f,
|
||||
0x54, 0x48, 0x55, 0x4d, 0x42, 0x50, 0x52, 0x49, 0x4e, 0x54, 0x2c, 0x20, 0x54, 0x48, 0x55, 0x4d,
|
||||
0x42, 0x50, 0x52, 0x49, 0x4e, 0x54, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x52, 0x1b, 0x63, 0x65, 0x72,
|
||||
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x31, 0x0a, 0x15, 0x61, 0x6c, 0x6c, 0x6f,
|
||||
0x77, 0x5f, 0x77, 0x65, 0x61, 0x6b, 0x5f, 0x74, 0x6c, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x57, 0x65,
|
||||
0x61, 0x6b, 0x54, 0x6c, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x63,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
|
||||
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43,
|
||||
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x1e, 0x63, 0x6c,
|
||||
0x72, 0x74, 0x4d, 0x61, 0x78, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x12,
|
||||
0x34, 0x0a, 0x16, 0x77, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f,
|
||||
0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x2c, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x14, 0x77, 0x61, 0x74, 0x63, 0x68, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x46, 0x72, 0x65, 0x71,
|
||||
0x75, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x37, 0x0a, 0x18, 0x77, 0x61, 0x74, 0x63, 0x68, 0x5f, 0x70,
|
||||
0x6c, 0x75, 0x67, 0x69, 0x6e, 0x5f, 0x62, 0x75, 0x66, 0x66, 0x65, 0x72, 0x5f, 0x73, 0x69, 0x7a,
|
||||
0x65, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x77, 0x61, 0x74, 0x63, 0x68, 0x50, 0x6c,
|
||||
0x75, 0x67, 0x69, 0x6e, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x22, 0xad,
|
||||
0x04, 0x0a, 0x0c, 0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x43, 0x65, 0x72, 0x74, 0x73, 0x12, 0x7f,
|
||||
0x0a, 0x17, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x68,
|
||||
0x75, 0x6d, 0x62, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x42,
|
||||
0x46, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x40, 0x12, 0x3e, 0x53, 0x48, 0x41, 0x32, 0x35, 0x36, 0x20,
|
||||
0x74, 0x68, 0x75, 0x6d, 0x62, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x63,
|
||||
0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74,
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x77, 0x69, 0x6c, 0x6c,
|
||||
0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x54, 0x68, 0x75, 0x6d, 0x62, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x73, 0x12,
|
||||
0xd5, 0x01, 0x0a, 0x1d, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f,
|
||||
0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x6f, 0x64,
|
||||
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x90, 0x01, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x89,
|
||||
0x01, 0x12, 0x86, 0x01, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
|
||||
0x77, 0x61, 0x79, 0x20, 0x69, 0x6e, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x56, 0x65, 0x6c,
|
||||
0x6f, 0x63, 0x69, 0x72, 0x61, 0x70, 0x74, 0x6f, 0x72, 0x20, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69,
|
||||
0x65, 0x73, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
|
||||
0x74, 0x65, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x65, 0x64, 0x20, 0x76, 0x61, 0x6c,
|
||||
0x75, 0x65, 0x73, 0x3a, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x28, 0x74, 0x68, 0x65, 0x20, 0x64, 0x65,
|
||||
0x66, 0x61, 0x75, 0x6c, 0x74, 0x29, 0x2c, 0x20, 0x50, 0x4b, 0x49, 0x5f, 0x4f, 0x52, 0x5f, 0x54,
|
||||
0x48, 0x55, 0x4d, 0x42, 0x50, 0x52, 0x49, 0x4e, 0x54, 0x2c, 0x20, 0x54, 0x48, 0x55, 0x4d, 0x42,
|
||||
0x50, 0x52, 0x49, 0x4e, 0x54, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x52, 0x1b, 0x63, 0x65, 0x72, 0x74,
|
||||
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x31, 0x0a, 0x15, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
|
||||
0x5f, 0x77, 0x65, 0x61, 0x6b, 0x5f, 0x74, 0x6c, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x57, 0x65, 0x61,
|
||||
0x6b, 0x54, 0x6c, 0x73, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x6c,
|
||||
0x69, 0x65, 0x6e, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||
0x5f, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x1b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x22,
|
||||
0x5d, 0x0a, 0x0a, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65,
|
||||
0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69,
|
||||
0x78, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0xf0,
|
||||
0x02, 0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 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, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73,
|
||||
0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70,
|
||||
0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x25,
|
||||
0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52,
|
||||
0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x21, 0x0a, 0x02, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50,
|
||||
0x6f, 0x69, 0x6e, 0x74, 0x52, 0x02, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d,
|
||||
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70,
|
||||
0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x73,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f,
|
||||
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x07, 0x20,
|
||||
0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x45,
|
||||
0x6e, 0x76, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x46, 0x75, 0x6e,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e,
|
||||
0x73, 0x22, 0xf7, 0x0c, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x0a, 0x0f,
|
||||
0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
|
||||
0x15, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x6f, 0x63,
|
||||
0x65, 0x72, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x46, 0x0a, 0x07, 0x76, 0x65, 0x72,
|
||||
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x1c, 0xe2, 0xfc, 0xe3, 0xc4,
|
||||
0x01, 0x16, 0x12, 0x14, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x66, 0x6f,
|
||||
0x72, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x4a, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x1d, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x17, 0x12, 0x15,
|
||||
0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a,
|
||||
0x03, 0x41, 0x50, 0x49, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x2e, 0x41, 0x50, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x2c, 0xe2, 0xfc,
|
||||
0xe3, 0xc4, 0x01, 0x26, 0x12, 0x24, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x52, 0x50, 0x43, 0x20, 0x41, 0x50, 0x49,
|
||||
0x20, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x52, 0x03, 0x41, 0x50, 0x49, 0x12,
|
||||
0x22, 0x0a, 0x03, 0x47, 0x55, 0x49, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03,
|
||||
0x47, 0x55, 0x49, 0x12, 0x1f, 0x0a, 0x02, 0x43, 0x41, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x41, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x52, 0x02, 0x43, 0x41, 0x12, 0x31, 0x0a, 0x08, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46,
|
||||
0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x46,
|
||||
0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x3d, 0x0a, 0x0e, 0x45, 0x78, 0x74, 0x72, 0x61,
|
||||
0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x45, 0x78, 0x74, 0x72, 0x61, 0x46, 0x72, 0x6f,
|
||||
0x6e, 0x74, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x52, 0x09, 0x44, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x32, 0x0a, 0x09,
|
||||
0x57, 0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x57, 0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b,
|
||||
0x12, 0x25, 0x0a, 0x04, 0x4d, 0x61, 0x69, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x61, 0x69, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x52, 0x04, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x2e, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x67, 0x69,
|
||||
0x6e, 0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07,
|
||||
0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x06, 0x4d, 0x69, 0x6e, 0x69, 0x6f,
|
||||
0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x4d, 0x69, 0x6e, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x4d, 0x69,
|
||||
0x6e, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18,
|
||||
0x14, 0x20, 0x01, 0x28, 0x08, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x45,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x20, 0x6c, 0x6f,
|
||||
0x67, 0x67, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x52, 0x07, 0x76,
|
||||
0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
|
||||
0x72, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x18, 0x16, 0x20,
|
||||
0x01, 0x28, 0x09, 0x42, 0x2c, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x26, 0x12, 0x24, 0x50, 0x61, 0x74,
|
||||
0x68, 0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63,
|
||||
0x65, 0x72, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73,
|
||||
0x2e, 0x52, 0x11, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x43,
|
||||
0x61, 0x63, 0x68, 0x65, 0x12, 0x6e, 0x0a, 0x0a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
|
||||
0x6e, 0x67, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x42, 0x35, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2d, 0x57, 0x68, 0x65, 0x72, 0x65,
|
||||
0x20, 0x74, 0x6f, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68,
|
||||
0x65, 0x75, 0x73, 0x20, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65,
|
||||
0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x52, 0x0a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
|
||||
0x72, 0x69, 0x6e, 0x67, 0x12, 0x7f, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x41, 0x70, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x42, 0x48, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x42, 0x12, 0x40, 0x49, 0x66, 0x20, 0x77, 0x65, 0x20,
|
||||
0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x69, 0x20, 0x63,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x20, 0x77, 0x65, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68,
|
||||
0x69, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6c, 0x6f, 0x62,
|
||||
0x61, 0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x09, 0x61, 0x70, 0x69, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x8f, 0x01, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x65, 0x78,
|
||||
0x65, 0x63, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x41, 0x75, 0x74, 0x6f, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
|
||||
0x5c, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x56, 0x12, 0x54, 0x49, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73,
|
||||
0x20, 0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, 0x65,
|
||||
0x20, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61,
|
||||
0x72, 0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x69, 0x76, 0x65,
|
||||
0x6e, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x61,
|
||||
0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x2e, 0x52, 0x08, 0x61,
|
||||
0x75, 0x74, 0x6f, 0x65, 0x78, 0x65, 0x63, 0x12, 0x50, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xe2, 0xfc,
|
||||
0xe3, 0xc4, 0x01, 0x29, 0x12, 0x27, 0x54, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x20, 0x28, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2c, 0x20, 0x77, 0x69, 0x6e,
|
||||
0x64, 0x6f, 0x77, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x29, 0x52, 0x0a, 0x73,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x62, 0x66,
|
||||
0x75, 0x73, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x20,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x62, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
|
||||
0x74, 0x73, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75,
|
||||
0x6c, 0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x22, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x6e,
|
||||
0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36, 0x0a, 0x0a,
|
||||
0x72, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b,
|
||||
0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x69,
|
||||
0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x70,
|
||||
0x69, 0x6e, 0x67, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x24,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6f,
|
||||
0x72, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x25, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f,
|
||||
0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12,
|
||||
0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x27, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x42, 0x34, 0x5a, 0x32, 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, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65,
|
||||
0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x43, 0x0a, 0x1e, 0x63, 0x6c, 0x69,
|
||||
0x65, 0x6e, 0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f,
|
||||
0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x1b, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x22, 0x5d,
|
||||
0x0a, 0x0a, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66,
|
||||
0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
|
||||
0x12, 0x1b, 0x0a, 0x09, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x74, 0x68, 0x54, 0x79, 0x70, 0x65, 0x22, 0xf0, 0x02,
|
||||
0x0a, 0x0f, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 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, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
|
||||
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65,
|
||||
0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x25, 0x0a,
|
||||
0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x04,
|
||||
0x66, 0x72, 0x6f, 0x6d, 0x12, 0x21, 0x0a, 0x02, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x6f,
|
||||
0x69, 0x6e, 0x74, 0x52, 0x02, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65,
|
||||
0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x73, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x6f, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73,
|
||||
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73,
|
||||
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x07, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x51, 0x4c, 0x45, 0x6e,
|
||||
0x76, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x03,
|
||||
0x28, 0x09, 0x52, 0x11, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x46, 0x75, 0x6e, 0x63,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65,
|
||||
0x64, 0x5f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x09, 0x52,
|
||||
0x0f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73,
|
||||
0x22, 0x96, 0x0d, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x0a, 0x0f, 0x61,
|
||||
0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x15,
|
||||
0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
|
||||
0x72, 0x74, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x46, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x1c, 0xe2, 0xfc, 0xe3, 0xc4, 0x01,
|
||||
0x16, 0x12, 0x14, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x72,
|
||||
0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x12, 0x4a, 0x0a, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x1d, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x17, 0x12, 0x15, 0x43,
|
||||
0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x06, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x50, 0x0a, 0x03,
|
||||
0x41, 0x50, 0x49, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x2e, 0x41, 0x50, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x2c, 0xe2, 0xfc, 0xe3,
|
||||
0xc4, 0x01, 0x26, 0x12, 0x24, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x67, 0x52, 0x50, 0x43, 0x20, 0x41, 0x50, 0x49, 0x20,
|
||||
0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x52, 0x03, 0x41, 0x50, 0x49, 0x12, 0x22,
|
||||
0x0a, 0x03, 0x47, 0x55, 0x49, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x55, 0x49, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x03, 0x47,
|
||||
0x55, 0x49, 0x12, 0x1f, 0x0a, 0x02, 0x43, 0x41, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x41, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52,
|
||||
0x02, 0x43, 0x41, 0x12, 0x31, 0x0a, 0x08, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x72,
|
||||
0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x08, 0x46, 0x72,
|
||||
0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x12, 0x3d, 0x0a, 0x0e, 0x45, 0x78, 0x74, 0x72, 0x61, 0x46,
|
||||
0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x1f, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x45, 0x78, 0x74, 0x72, 0x61, 0x46, 0x72, 0x6f, 0x6e,
|
||||
0x74, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x34, 0x0a, 0x09, 0x44, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x2e, 0x44, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x52, 0x09, 0x44, 0x61, 0x74, 0x61, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x32, 0x0a, 0x09, 0x57,
|
||||
0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b,
|
||||
0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x57, 0x72, 0x69, 0x74, 0x65, 0x62, 0x61, 0x63, 0x6b, 0x12,
|
||||
0x25, 0x0a, 0x04, 0x4d, 0x61, 0x69, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x61, 0x69, 0x6c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x52, 0x04, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x2e, 0x0a, 0x07, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e,
|
||||
0x67, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x07, 0x4c,
|
||||
0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x12, 0x2b, 0x0a, 0x06, 0x4d, 0x69, 0x6e, 0x69, 0x6f, 0x6e,
|
||||
0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d,
|
||||
0x69, 0x6e, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x4d, 0x69, 0x6e,
|
||||
0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x14,
|
||||
0x20, 0x01, 0x28, 0x08, 0x42, 0x26, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x20, 0x12, 0x1e, 0x45, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x20, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x20, 0x6c, 0x6f, 0x67,
|
||||
0x67, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x2e, 0x52, 0x07, 0x76, 0x65,
|
||||
0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x5c, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72,
|
||||
0x74, 0x5f, 0x63, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x18, 0x16, 0x20, 0x01,
|
||||
0x28, 0x09, 0x42, 0x2c, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x26, 0x12, 0x24, 0x50, 0x61, 0x74, 0x68,
|
||||
0x20, 0x74, 0x6f, 0x20, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65,
|
||||
0x72, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e,
|
||||
0x52, 0x11, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x65, 0x72, 0x74, 0x43, 0x65, 0x72, 0x74, 0x43, 0x61,
|
||||
0x63, 0x68, 0x65, 0x12, 0x6e, 0x0a, 0x0a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e,
|
||||
0x67, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x42, 0x35, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x2f, 0x12, 0x2d, 0x57, 0x68, 0x65, 0x72, 0x65, 0x20,
|
||||
0x74, 0x6f, 0x20, 0x62, 0x69, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65,
|
||||
0x75, 0x73, 0x20, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e,
|
||||
0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x2e, 0x52, 0x0a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
|
||||
0x69, 0x6e, 0x67, 0x12, 0x7f, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x41, 0x70, 0x69, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42,
|
||||
0x48, 0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x42, 0x12, 0x40, 0x49, 0x66, 0x20, 0x77, 0x65, 0x20, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x61, 0x70, 0x69, 0x20, 0x63, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x20, 0x77, 0x65, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x69,
|
||||
0x73, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6c, 0x6f, 0x62, 0x61,
|
||||
0x6c, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x52, 0x09, 0x61, 0x70, 0x69, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x8f, 0x01, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x65, 0x78, 0x65,
|
||||
0x63, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x41, 0x75, 0x74, 0x6f, 0x45, 0x78, 0x65, 0x63, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x42, 0x5c,
|
||||
0xe2, 0xfc, 0xe3, 0xc4, 0x01, 0x56, 0x12, 0x54, 0x49, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20,
|
||||
0x69, 0x73, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x20, 0x77, 0x65, 0x20,
|
||||
0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72,
|
||||
0x79, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x69, 0x76, 0x65, 0x6e,
|
||||
0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x61, 0x75,
|
||||
0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x6c, 0x79, 0x2e, 0x52, 0x08, 0x61, 0x75,
|
||||
0x74, 0x6f, 0x65, 0x78, 0x65, 0x63, 0x12, 0x50, 0x0a, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
|
||||
0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2f, 0xe2, 0xfc, 0xe3,
|
||||
0xc4, 0x01, 0x29, 0x12, 0x27, 0x54, 0x79, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x20, 0x28, 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2c, 0x20, 0x77, 0x69, 0x6e, 0x64,
|
||||
0x6f, 0x77, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x72, 0x77, 0x69, 0x6e, 0x29, 0x52, 0x0a, 0x73, 0x65,
|
||||
0x72, 0x76, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x6f, 0x62, 0x66, 0x75,
|
||||
0x73, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x20, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x62, 0x66, 0x75, 0x73, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74,
|
||||
0x73, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
|
||||
0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x52, 0x08, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c,
|
||||
0x74, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x22, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x6e, 0x61,
|
||||
0x6c, 0x79, 0x73, 0x69, 0x73, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x36, 0x0a, 0x0a, 0x72,
|
||||
0x65, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x23, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||
0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e,
|
||||
0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0a, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x70, 0x69,
|
||||
0x6e, 0x67, 0x73, 0x12, 0x15, 0x0a, 0x06, 0x6f, 0x72, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x24, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x05, 0x6f, 0x72, 0x67, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x72,
|
||||
0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x25, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x72,
|
||||
0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x5f, 0x6d,
|
||||
0x6f, 0x64, 0x65, 0x18, 0x29, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x64, 0x65, 0x62, 0x75, 0x67,
|
||||
0x4d, 0x6f, 0x64, 0x65, 0x12, 0x37, 0x0a, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x18, 0x26, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53,
|
||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x52, 0x08, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x18, 0x27, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x08, 0x6c, 0x6f, 0x63, 0x6b, 0x64, 0x6f, 0x77, 0x6e, 0x42, 0x34, 0x5a, 0x32, 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, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -1098,9 +1098,17 @@ message Defaults {
|
||||
// its own but if this is set, we prevent any external access.
|
||||
bool disable_inventory_service_external_access = 34;
|
||||
|
||||
// Controls how exports work (creating hunt or colletion exports to a zip file).
|
||||
// Controls how exports work (creating hunt or colletion exports
|
||||
// to a zip file).
|
||||
int64 export_concurrency = 40;
|
||||
int64 export_max_timeout_sec = 41;
|
||||
|
||||
// Watch plugin frequency sleep time in seconds: How often
|
||||
// watch_syslog() will check for changes (default 3).
|
||||
int64 watch_plugin_frequency = 44;
|
||||
|
||||
// Maximum length of the line that will be parsed (16kb)
|
||||
int64 watch_plugin_buffer_size = 45;
|
||||
}
|
||||
|
||||
// Configures crypto preferences
|
||||
@@ -1281,7 +1289,7 @@ message Config {
|
||||
// does not know or use its own org id.
|
||||
string org_id = 36;
|
||||
string org_name = 37;
|
||||
|
||||
bool debug_mode = 41;
|
||||
|
||||
// The services that will run at initialization. Note this is not
|
||||
// set in the config file by the user but is propagated from the
|
||||
|
||||
@@ -106,6 +106,7 @@ var (
|
||||
"defaults.max_batch_wait",
|
||||
"defaults.disable_inventory_service_external_access",
|
||||
"lockdown",
|
||||
"debug_mode",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -506,7 +506,7 @@ GUI:
|
||||
- administrator
|
||||
|
||||
# How long to keep the session alive between auth flows - default 24 hours
|
||||
default_session_expiry_min: 8000
|
||||
default_session_expiry_min: 1440
|
||||
|
||||
# Used by the multi authenticator to provide multiple
|
||||
# authenticators. NOTE: Sub authenticators must be oauth based
|
||||
@@ -1188,6 +1188,21 @@ defaults:
|
||||
export_concurrency: 10
|
||||
export_max_timeout_sec: 600
|
||||
|
||||
# The server maintains an index of all hunts in order to quickly
|
||||
# allow the GUI to filter/sort them. This setting controls how often
|
||||
# to rebuild the hunt index (default 600 sec). You probably dont
|
||||
# need to change it.
|
||||
hunt_dispatcher_refresh_sec: 600
|
||||
|
||||
# Total number of cell versions we keep for undo/redo support.
|
||||
notebook_versions: 5
|
||||
|
||||
# Watch plugin frequency sleep time in seconds: How often
|
||||
# watch_syslog() will check for changes (default 3).
|
||||
watch_plugin_frequency: 3
|
||||
|
||||
# Maximum length of the line that will be parsed (16kb)
|
||||
watch_plugin_buffer_size: 16384
|
||||
|
||||
# The Velociraptor server may be placed into "lockdown" mode. While in
|
||||
# lockdown mode certain permissions are denied - even for
|
||||
@@ -1197,6 +1212,9 @@ defaults:
|
||||
# lockdown to false and restarting the server.
|
||||
lockdown: false
|
||||
|
||||
# This will be set when Velociraptor is started with the --debug flag.
|
||||
debug_mode: false
|
||||
|
||||
# This configuration applies for minions. On minions this will
|
||||
# override the settings elsewhere in the config file allowing an easy
|
||||
# way to manage the difference between minions and master nodes.
|
||||
|
||||
@@ -1425,6 +1425,37 @@
|
||||
tools on the client.
|
||||
|
||||
https://docs.velociraptor.app/docs/extending_vql/#using-external-tools
|
||||
|
||||
NOTE: The plugin receives an array of arguments which are passed
|
||||
to the `execve()` system call as an array (on Windows they are
|
||||
properly escaped into a command line). This means that you do not
|
||||
need to escape or quote any special characters in the command.
|
||||
|
||||
We noticed people often do this or variations on it:
|
||||
```vql
|
||||
LET PathToCacls = "C:/Program Files"
|
||||
LET CommandLine <= "cacls.exe " + '"' + PathToCacls + '"'
|
||||
SELECT * FROM execve(argv=["powershell", "-c", CommandLine])
|
||||
```
|
||||
|
||||
While this appears to work it is incorrect, fragile and
|
||||
susceptible to a simple shell injection (for example if the
|
||||
`PathToCacls` contains quotes).
|
||||
|
||||
As a rule we prefer to not run commands through the shell at all
|
||||
since it is not needed and unsafe. The correct approach is always
|
||||
to split the `argv` into an array of distinct arguments:
|
||||
|
||||
```vql
|
||||
LET PathToCacls = "C:/Program Files"
|
||||
SELECT * FROM execve(argv=["cacls.exe", PathToCacls])
|
||||
```
|
||||
|
||||
This calls the program directly and is not susceptible to escaping
|
||||
or quoting issues (since there is no shell involved). Additionally
|
||||
it does not invoke powershell which means that any execution
|
||||
artifacts are not trampled by this VQL.
|
||||
|
||||
type: Plugin
|
||||
args:
|
||||
- name: argv
|
||||
@@ -6896,14 +6927,14 @@
|
||||
- name: xattr
|
||||
description: |
|
||||
Query a file for the specified extended attribute.
|
||||
|
||||
If no attributes are provided, this function will return all extended attributes
|
||||
|
||||
If no attributes are provided, this function will return all extended attributes
|
||||
for the file.
|
||||
|
||||
|
||||
Please note: this API is not reliable, so please provided extended attributes
|
||||
where possible.
|
||||
|
||||
Note: This function only works on Mac and Linux.
|
||||
Note: This function only works on Mac and Linux.
|
||||
type: Function
|
||||
args:
|
||||
- name: filename
|
||||
@@ -7057,4 +7088,3 @@
|
||||
category: plugin
|
||||
metadata:
|
||||
permissions: FILESYSTEM_READ
|
||||
|
||||
|
||||
+23
-27
@@ -27,6 +27,7 @@ import (
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -47,10 +48,12 @@ import (
|
||||
"www.velocidex.com/golang/velociraptor/constants"
|
||||
crypto_proto "www.velocidex.com/golang/velociraptor/crypto/proto"
|
||||
"www.velocidex.com/golang/velociraptor/logging"
|
||||
http_utils "www.velocidex.com/golang/velociraptor/utils/http"
|
||||
)
|
||||
|
||||
var (
|
||||
packetTooLargeError = errors.New("Packet too large!")
|
||||
notFoundError = errors.New("Not Found")
|
||||
|
||||
currentConnections = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "client_comms_current_connections",
|
||||
@@ -684,33 +687,12 @@ func send_client_messages(server_obj *Server) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// Record the status of the request so we can log it.
|
||||
type statusRecorder struct {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
status int
|
||||
error []byte
|
||||
}
|
||||
|
||||
func (self *statusRecorder) WriteHeader(code int) {
|
||||
self.status = code
|
||||
self.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (self *statusRecorder) Write(buf []byte) (int, error) {
|
||||
if self.status == 500 {
|
||||
self.error = buf
|
||||
}
|
||||
|
||||
return self.ResponseWriter.Write(buf)
|
||||
}
|
||||
|
||||
func GetLoggingHandler(config_obj *config_proto.Config,
|
||||
handler string) func(http.Handler) http.Handler {
|
||||
logger := logging.GetLogger(config_obj, &logging.FrontendComponent)
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rec := &statusRecorder{
|
||||
rec := &http_utils.StatusRecorder{
|
||||
w,
|
||||
w.(http.Flusher),
|
||||
200, nil}
|
||||
@@ -722,7 +704,7 @@ func GetLoggingHandler(config_obj *config_proto.Config,
|
||||
"url": r.URL.Path,
|
||||
"remote": r.RemoteAddr,
|
||||
"user-agent": r.UserAgent(),
|
||||
"status": rec.status,
|
||||
"status": rec.Status,
|
||||
"handler": handler,
|
||||
}).Info("Access to handler")
|
||||
}()
|
||||
@@ -740,7 +722,7 @@ func downloadPublic(
|
||||
// make sure the prefix is correct
|
||||
for i, p := range prefix {
|
||||
if len(components) <= i || p != components[i] {
|
||||
returnError(w, 404, "Not Found")
|
||||
returnError(config_obj, w, 404, notFoundError)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -748,7 +730,7 @@ func downloadPublic(
|
||||
file_store_factory := file_store.GetFileStore(config_obj)
|
||||
fd, err := file_store_factory.ReadFile(path_spec)
|
||||
if err != nil {
|
||||
returnError(w, 404, err.Error())
|
||||
returnError(config_obj, w, 404, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -764,9 +746,23 @@ func downloadPublic(
|
||||
})
|
||||
}
|
||||
|
||||
func returnError(w http.ResponseWriter, code int, message string) {
|
||||
func returnError(
|
||||
config_obj *config_proto.Config,
|
||||
w http.ResponseWriter, code int, err error) {
|
||||
w.WriteHeader(code)
|
||||
_, _ = w.Write([]byte(html.EscapeString(message)))
|
||||
|
||||
if config_obj.DebugMode {
|
||||
_, _ = w.Write([]byte(html.EscapeString(err.Error())))
|
||||
return
|
||||
}
|
||||
|
||||
// In production provide generic errors.
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
_, _ = w.Write([]byte("Not Found"))
|
||||
|
||||
} else {
|
||||
_, _ = w.Write([]byte("Error"))
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate QPS
|
||||
|
||||
+3
-2
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
http_utils "www.velocidex.com/golang/velociraptor/utils/http"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -20,13 +21,13 @@ var (
|
||||
|
||||
func RecordHTTPStats(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
rec := &statusRecorder{
|
||||
rec := &http_utils.StatusRecorder{
|
||||
w,
|
||||
w.(http.Flusher),
|
||||
200, nil}
|
||||
|
||||
next.ServeHTTP(rec, r)
|
||||
status := fmt.Sprintf("%v", rec.status)
|
||||
status := fmt.Sprintf("%v", rec.Status)
|
||||
httpErrorStatusCounters.WithLabelValues(status).Inc()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package http
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Record the status of the request so we can log it.
|
||||
type StatusRecorder struct {
|
||||
http.ResponseWriter
|
||||
http.Flusher
|
||||
Status int
|
||||
Error []byte
|
||||
}
|
||||
|
||||
func (self *StatusRecorder) WriteHeader(code int) {
|
||||
self.Status = code
|
||||
self.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
func (self *StatusRecorder) Write(buf []byte) (int, error) {
|
||||
if self.Status == 500 {
|
||||
self.Error = buf
|
||||
}
|
||||
|
||||
return self.ResponseWriter.Write(buf)
|
||||
}
|
||||
+103
-4
@@ -31,11 +31,14 @@ import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"www.velocidex.com/golang/velociraptor/accessors"
|
||||
"www.velocidex.com/golang/velociraptor/acls"
|
||||
"www.velocidex.com/golang/velociraptor/artifacts"
|
||||
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
|
||||
"www.velocidex.com/golang/velociraptor/json"
|
||||
utils "www.velocidex.com/golang/velociraptor/utils"
|
||||
"www.velocidex.com/golang/velociraptor/vql"
|
||||
vql_subsystem "www.velocidex.com/golang/velociraptor/vql"
|
||||
"www.velocidex.com/golang/velociraptor/vql/functions"
|
||||
"www.velocidex.com/golang/velociraptor/vql/parsers/syslog"
|
||||
"www.velocidex.com/golang/vfilter"
|
||||
"www.velocidex.com/golang/vfilter/arg_parser"
|
||||
)
|
||||
@@ -526,9 +529,10 @@ func (self _IndexAssociativeProtocol) GetMembers(
|
||||
}
|
||||
|
||||
type WriteJSONPluginArgs struct {
|
||||
Filename *accessors.OSPath `vfilter:"required,field=filename,doc=CSV files to open"`
|
||||
Accessor string `vfilter:"optional,field=accessor,doc=The accessor to use"`
|
||||
Query vfilter.StoredQuery `vfilter:"required,field=query,doc=query to write into the file."`
|
||||
Filename *accessors.OSPath `vfilter:"required,field=filename,doc=CSV files to open"`
|
||||
Accessor string `vfilter:"optional,field=accessor,doc=The accessor to use"`
|
||||
Query vfilter.StoredQuery `vfilter:"required,field=query,doc=query to write into the file."`
|
||||
BufferSize int `vfilter:"optional,field=buffer_size,doc=Maximum size of buffer before flushing to file."`
|
||||
}
|
||||
|
||||
type WriteJSONPlugin struct{}
|
||||
@@ -549,6 +553,10 @@ func (self WriteJSONPlugin) Call(
|
||||
return
|
||||
}
|
||||
|
||||
if arg.BufferSize == 0 {
|
||||
arg.BufferSize = BUFF_SIZE
|
||||
}
|
||||
|
||||
var writer *bufio.Writer
|
||||
|
||||
switch arg.Accessor {
|
||||
@@ -575,7 +583,7 @@ func (self WriteJSONPlugin) Call(
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
writer = bufio.NewWriterSize(file, BUFF_SIZE)
|
||||
writer = bufio.NewWriterSize(file, arg.BufferSize)
|
||||
defer writer.Flush()
|
||||
|
||||
default:
|
||||
@@ -613,6 +621,96 @@ func (self WriteJSONPlugin) Info(scope vfilter.Scope, type_map *vfilter.TypeMap)
|
||||
}
|
||||
}
|
||||
|
||||
type WatchJsonlPlugin struct{}
|
||||
|
||||
func (self WatchJsonlPlugin) Info(scope vfilter.Scope, type_map *vfilter.TypeMap) *vfilter.PluginInfo {
|
||||
return &vfilter.PluginInfo{
|
||||
Name: "watch_jsonl",
|
||||
Doc: "Watch a jsonl file and stream events from it.",
|
||||
ArgType: type_map.AddType(scope, &syslog.ScannerPluginArgs{}),
|
||||
Metadata: vql.VQLMetadata().Permissions(acls.FILESYSTEM_READ).Build(),
|
||||
}
|
||||
}
|
||||
|
||||
func (self WatchJsonlPlugin) Call(
|
||||
ctx context.Context, scope vfilter.Scope,
|
||||
args *ordereddict.Dict) <-chan vfilter.Row {
|
||||
output_chan := make(chan vfilter.Row)
|
||||
|
||||
go func() {
|
||||
defer close(output_chan)
|
||||
arg := &syslog.ScannerPluginArgs{}
|
||||
err := arg_parser.ExtractArgsWithContext(ctx, scope, args, arg)
|
||||
if err != nil {
|
||||
scope.Log("watch_jsonl: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
err = vql_subsystem.CheckFilesystemAccess(scope, arg.Accessor)
|
||||
if err != nil {
|
||||
scope.Log("watch_jsonl: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// This plugin needs to be running on clients which have no
|
||||
// server config object.
|
||||
client_config_obj, ok := artifacts.GetConfig(scope)
|
||||
if !ok {
|
||||
scope.Log("watch_jsonl: unable to get config")
|
||||
return
|
||||
}
|
||||
|
||||
config_obj := &config_proto.Config{Client: client_config_obj}
|
||||
|
||||
event_channel := make(chan vfilter.Row)
|
||||
|
||||
// Register the output channel as a listener to the
|
||||
// global event.
|
||||
for _, filename := range arg.Filenames {
|
||||
cancel := syslog.GlobalSyslogService(config_obj).Register(
|
||||
filename, arg.Accessor, ctx, scope,
|
||||
event_channel)
|
||||
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
// Wait until the query is complete.
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case event, ok := <-event_channel:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Get the line from the event
|
||||
line := vql_subsystem.GetStringFromRow(scope, event, "Line")
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
json_event := ordereddict.NewDict()
|
||||
err := json.Unmarshal([]byte(line), json_event)
|
||||
if err != nil {
|
||||
scope.Log("Invalid jsonl: %v\n", line)
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case output_chan <- json_event:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return output_chan
|
||||
}
|
||||
|
||||
func init() {
|
||||
vql_subsystem.RegisterFunction(&ParseJsonFunction{})
|
||||
vql_subsystem.RegisterFunction(&ParseJsonArray{})
|
||||
@@ -623,4 +721,5 @@ func init() {
|
||||
vql_subsystem.RegisterPlugin(&ParseJsonArrayPlugin{})
|
||||
vql_subsystem.RegisterPlugin(&ParseJsonlPlugin{})
|
||||
vql_subsystem.RegisterPlugin(&WriteJSONPlugin{})
|
||||
vql_subsystem.RegisterPlugin(&WatchJsonlPlugin{})
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ func (self WatchAuditdPlugin) Call(
|
||||
}
|
||||
}()
|
||||
|
||||
scanner := _WatchSyslogPlugin{}
|
||||
scanner := WatchSyslogPlugin{}
|
||||
for row := range scanner.Call(ctx, scope, args) {
|
||||
line, pres := scope.Associative(row, "Line")
|
||||
if !pres {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"Short Lines": [
|
||||
{
|
||||
"Line": "0123456701"
|
||||
},
|
||||
{
|
||||
"Line": "0123456702"
|
||||
},
|
||||
{
|
||||
"Line": "0123456703"
|
||||
}
|
||||
],
|
||||
"Long Lines": [
|
||||
{
|
||||
"Line": "01234567890123456701"
|
||||
},
|
||||
{
|
||||
"Line": "01234567890123456702"
|
||||
},
|
||||
{
|
||||
"Line": "01234567890123456703"
|
||||
}
|
||||
],
|
||||
"Broken Line": [
|
||||
{
|
||||
"Line": "0123456no crlfand this is crlf"
|
||||
}
|
||||
],
|
||||
"Broken Buffer": [
|
||||
{
|
||||
"Line": "01234567890123456701,01234567890123456702,01234567"
|
||||
},
|
||||
{
|
||||
"Line": "890123456703"
|
||||
}
|
||||
],
|
||||
"Lines after file rewind": [
|
||||
{
|
||||
"Line": "0123456701"
|
||||
},
|
||||
{
|
||||
"Line": "0123456702"
|
||||
},
|
||||
{
|
||||
"Line": "0123456703"
|
||||
}
|
||||
],
|
||||
"Empty lines": [
|
||||
{
|
||||
"Line": ""
|
||||
},
|
||||
{
|
||||
"Line": ""
|
||||
},
|
||||
{
|
||||
"Line": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -94,9 +94,9 @@ func (self ScannerPlugin) Call(
|
||||
return output_chan
|
||||
}
|
||||
|
||||
type _WatchSyslogPlugin struct{}
|
||||
type WatchSyslogPlugin struct{}
|
||||
|
||||
func (self _WatchSyslogPlugin) Call(
|
||||
func (self WatchSyslogPlugin) Call(
|
||||
ctx context.Context,
|
||||
scope vfilter.Scope,
|
||||
args *ordereddict.Dict) <-chan vfilter.Row {
|
||||
@@ -160,7 +160,7 @@ func (self _WatchSyslogPlugin) Call(
|
||||
return output_chan
|
||||
}
|
||||
|
||||
func (self _WatchSyslogPlugin) Info(scope vfilter.Scope, type_map *vfilter.TypeMap) *vfilter.PluginInfo {
|
||||
func (self WatchSyslogPlugin) Info(scope vfilter.Scope, type_map *vfilter.TypeMap) *vfilter.PluginInfo {
|
||||
return &vfilter.PluginInfo{
|
||||
Name: "watch_syslog",
|
||||
Doc: "Watch a syslog file and stream events from it. ",
|
||||
@@ -193,6 +193,6 @@ func maybeOpenGzip(scope vfilter.Scope,
|
||||
}
|
||||
|
||||
func init() {
|
||||
vql_subsystem.RegisterPlugin(&_WatchSyslogPlugin{})
|
||||
vql_subsystem.RegisterPlugin(&WatchSyslogPlugin{})
|
||||
vql_subsystem.RegisterPlugin(&ScannerPlugin{})
|
||||
}
|
||||
|
||||
+107
-50
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -16,11 +17,6 @@ import (
|
||||
"www.velocidex.com/golang/vfilter"
|
||||
)
|
||||
|
||||
const (
|
||||
FREQUENCY = 3 * time.Second
|
||||
BUFFER_SIZE = 16 * 1024
|
||||
)
|
||||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
gSyslogService *SyslogWatcherService
|
||||
@@ -43,10 +39,30 @@ type SyslogWatcherService struct {
|
||||
|
||||
config_obj *config_proto.Config
|
||||
registrations map[string][]*Handle
|
||||
|
||||
sleep_time time.Duration
|
||||
buffer_size int64
|
||||
|
||||
monitor_count int
|
||||
}
|
||||
|
||||
func NewSyslogWatcherService(config_obj *config_proto.Config) *SyslogWatcherService {
|
||||
|
||||
sleep_time := 3 * time.Second
|
||||
buffer_size := int64(16 * 1024)
|
||||
if config_obj.Defaults != nil {
|
||||
if config_obj.Defaults.WatchPluginFrequency > 0 {
|
||||
sleep_time = time.Second * time.Duration(
|
||||
config_obj.Defaults.WatchPluginFrequency)
|
||||
}
|
||||
if config_obj.Defaults.WatchPluginBufferSize > 0 {
|
||||
buffer_size = config_obj.Defaults.WatchPluginBufferSize
|
||||
}
|
||||
}
|
||||
|
||||
return &SyslogWatcherService{
|
||||
sleep_time: sleep_time,
|
||||
buffer_size: buffer_size,
|
||||
config_obj: config_obj,
|
||||
registrations: make(map[string][]*Handle),
|
||||
}
|
||||
@@ -126,7 +142,7 @@ func (self *SyslogWatcherService) StartMonitoring(
|
||||
|
||||
cursor = self.monitorOnce(filename, accessor_name, accessor, cursor)
|
||||
|
||||
time.Sleep(FREQUENCY)
|
||||
time.Sleep(self.sleep_time)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +164,7 @@ func (self *SyslogWatcherService) findLastLineOffset(
|
||||
defer fd.Close()
|
||||
|
||||
cursor.file_size = stat.Size()
|
||||
last_offset := cursor.file_size - BUFFER_SIZE
|
||||
last_offset := cursor.file_size - self.buffer_size
|
||||
if last_offset < 0 {
|
||||
last_offset = 0
|
||||
}
|
||||
@@ -159,7 +175,7 @@ func (self *SyslogWatcherService) findLastLineOffset(
|
||||
return cursor
|
||||
}
|
||||
|
||||
buff := make([]byte, BUFFER_SIZE)
|
||||
buff := make([]byte, self.buffer_size)
|
||||
n, err := fd.Read(buff)
|
||||
if err != nil && err != io.EOF {
|
||||
return cursor
|
||||
@@ -182,7 +198,10 @@ func (self *SyslogWatcherService) monitorOnce(
|
||||
cursor *Cursor) *Cursor {
|
||||
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
defer func() {
|
||||
self.monitor_count++
|
||||
self.mu.Unlock()
|
||||
}()
|
||||
|
||||
stat, err := accessor.LstatWithOSPath(filename)
|
||||
if err != nil {
|
||||
@@ -198,7 +217,7 @@ func (self *SyslogWatcherService) monitorOnce(
|
||||
// file was truncated.
|
||||
if stat.Size() < cursor.file_size {
|
||||
logger := logging.GetLogger(self.config_obj, &logging.ClientComponent)
|
||||
logger.Info("File size (%v) is smaller than last know size (%v) - assuming file was truncated. Will start reading at the start again.",
|
||||
logger.Info("File size (%v) is smaller than last known size (%v) - assuming file was truncated. Will start reading at the start again.",
|
||||
stat.Size(), cursor.file_size)
|
||||
cursor.last_line_offset = 0
|
||||
}
|
||||
@@ -217,55 +236,86 @@ func (self *SyslogWatcherService) monitorOnce(
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
// File must be seekable
|
||||
pos, err := fd.Seek(cursor.last_line_offset, 0)
|
||||
if err != nil {
|
||||
return cursor
|
||||
}
|
||||
for {
|
||||
// Only read up to the last offset in case the file grows more.
|
||||
to_read := cursor.file_size - cursor.last_line_offset
|
||||
if to_read > self.buffer_size {
|
||||
to_read = self.buffer_size
|
||||
}
|
||||
|
||||
// File is truncated, start reading from the front again.
|
||||
if cursor.last_line_offset != pos {
|
||||
cursor.last_line_offset = 0
|
||||
return cursor
|
||||
}
|
||||
if to_read == 0 {
|
||||
return cursor
|
||||
}
|
||||
|
||||
buff := make([]byte, BUFFER_SIZE)
|
||||
n, err := fd.Read(buff)
|
||||
if err != nil && err != io.EOF {
|
||||
return cursor
|
||||
}
|
||||
// File must be seekable
|
||||
pos, err := fd.Seek(cursor.last_line_offset, os.SEEK_SET)
|
||||
if err != nil {
|
||||
return cursor
|
||||
}
|
||||
|
||||
buff = buff[:n]
|
||||
offset := 0
|
||||
// File is truncated, start reading from the front again.
|
||||
if cursor.last_line_offset != pos {
|
||||
cursor.last_line_offset = 0
|
||||
return cursor
|
||||
}
|
||||
|
||||
// Read whole lines inside the buffer
|
||||
for len(buff)-offset > 0 {
|
||||
new_lf := bytes.IndexByte(buff[offset:], '\n')
|
||||
if new_lf > 0 {
|
||||
new_handles := self.distributeLine(
|
||||
string(buff[offset:offset+new_lf]), filename, key, handles)
|
||||
buff := make([]byte, to_read)
|
||||
n, err := fd.Read(buff)
|
||||
if err != nil && err != io.EOF {
|
||||
return cursor
|
||||
}
|
||||
|
||||
// No more listeners - we dont care any more.
|
||||
if len(new_handles) == 0 {
|
||||
delete(self.registrations, key)
|
||||
buff = buff[:n]
|
||||
|
||||
// Read whole lines inside the buffer
|
||||
for len(buff) > 0 {
|
||||
new_lf := bytes.IndexByte(buff, '\n')
|
||||
if new_lf >= 0 {
|
||||
cursor.last_line_offset += int64(new_lf) + 1
|
||||
|
||||
handles = self.distributeLine(
|
||||
string(buff[:new_lf]), filename, key, handles)
|
||||
|
||||
// No more listeners - we dont care any more.
|
||||
if len(handles) == 0 {
|
||||
return cursor
|
||||
}
|
||||
|
||||
// Advance the cursor to the next line
|
||||
buff = buff[new_lf+1:]
|
||||
|
||||
// Get next line
|
||||
continue
|
||||
}
|
||||
|
||||
// The entire buffer does not contain lf at all - we skip
|
||||
// the entire buffer and hope to get a line on the next
|
||||
// read.
|
||||
if len(buff) == n {
|
||||
|
||||
// The last line is just too long for the buffer. We
|
||||
// break it up into multiple lines to fit.
|
||||
if cursor.file_size-cursor.last_line_offset >
|
||||
self.buffer_size {
|
||||
cursor.last_line_offset += int64(len(buff))
|
||||
|
||||
handles = self.distributeLine(
|
||||
string(buff), filename, key, handles)
|
||||
|
||||
// No more listeners - we dont care any more.
|
||||
if len(handles) == 0 {
|
||||
return cursor
|
||||
}
|
||||
|
||||
// Drop the buffer and read some more.
|
||||
break
|
||||
}
|
||||
|
||||
return cursor
|
||||
}
|
||||
|
||||
// Update the registrations - possibly
|
||||
// omitting finished listeners.
|
||||
self.registrations[key] = new_handles
|
||||
handles = new_handles
|
||||
|
||||
cursor.last_line_offset += int64(new_lf) + 1
|
||||
offset += new_lf + 1
|
||||
|
||||
} else {
|
||||
// The buffer does not contain lf at all - we
|
||||
// skip the entire buffer and hope to get a
|
||||
// line on the next read.
|
||||
cursor.last_line_offset += int64(len(buff) - offset)
|
||||
return cursor
|
||||
// Abandon this buffer and try again
|
||||
break
|
||||
}
|
||||
}
|
||||
return cursor
|
||||
@@ -290,6 +340,13 @@ func (self *SyslogWatcherService) distributeLine(
|
||||
}
|
||||
}
|
||||
|
||||
// Update the registrations - possibly omitting finished
|
||||
// listeners.
|
||||
if len(new_handles) == 0 {
|
||||
delete(self.registrations, key)
|
||||
}
|
||||
self.registrations[key] = new_handles
|
||||
|
||||
return new_handles
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
package syslog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Velocidex/ordereddict"
|
||||
"github.com/sebdah/goldie"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"www.velocidex.com/golang/velociraptor/accessors"
|
||||
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
|
||||
"www.velocidex.com/golang/velociraptor/file_store/test_utils"
|
||||
"www.velocidex.com/golang/velociraptor/json"
|
||||
"www.velocidex.com/golang/velociraptor/logging"
|
||||
"www.velocidex.com/golang/velociraptor/services"
|
||||
"www.velocidex.com/golang/velociraptor/vql/acl_managers"
|
||||
"www.velocidex.com/golang/velociraptor/vtesting"
|
||||
"www.velocidex.com/golang/velociraptor/vtesting/assert"
|
||||
"www.velocidex.com/golang/vfilter"
|
||||
|
||||
_ "www.velocidex.com/golang/velociraptor/accessors/file"
|
||||
)
|
||||
|
||||
type SyslogWatcherTestSuite struct {
|
||||
test_utils.TestSuite
|
||||
|
||||
mu sync.Mutex
|
||||
result []vfilter.Row
|
||||
output_chan chan vfilter.Row
|
||||
scope vfilter.Scope
|
||||
temp_file string
|
||||
filename *accessors.OSPath
|
||||
wg sync.WaitGroup
|
||||
cancel func()
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) SetupTest() {
|
||||
self.TestSuite.SetupTest()
|
||||
|
||||
// Change the normal frequency to very long so it does not
|
||||
// interfere with our test.
|
||||
self.ConfigObj.Defaults = &config_proto.Defaults{
|
||||
WatchPluginFrequency: 10000,
|
||||
|
||||
// Make the buffer small so we can test exceeding it
|
||||
WatchPluginBufferSize: 50,
|
||||
}
|
||||
|
||||
self.output_chan = make(chan vfilter.Row)
|
||||
|
||||
ctx, cancel := context.WithCancel(self.Ctx)
|
||||
self.cancel = cancel
|
||||
|
||||
self.wg.Add(1)
|
||||
go func() {
|
||||
defer self.wg.Done()
|
||||
defer close(self.output_chan)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
||||
case item, ok := <-self.output_chan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
self.mu.Lock()
|
||||
self.result = append(self.result, item)
|
||||
self.mu.Unlock()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
builder := services.ScopeBuilder{
|
||||
Config: self.ConfigObj,
|
||||
ACLManager: acl_managers.NullACLManager{},
|
||||
Logger: logging.NewPlainLogger(
|
||||
self.ConfigObj, &logging.FrontendComponent),
|
||||
Env: ordereddict.NewDict(),
|
||||
}
|
||||
|
||||
manager, err := services.GetRepositoryManager(self.ConfigObj)
|
||||
assert.NoError(self.T(), err)
|
||||
|
||||
self.scope = manager.BuildScope(builder)
|
||||
|
||||
fd, err := ioutil.TempFile("", "tmp")
|
||||
assert.NoError(self.T(), err)
|
||||
fd.Close()
|
||||
|
||||
self.temp_file = fd.Name()
|
||||
|
||||
self.truncateFile()
|
||||
|
||||
self.filename, err = accessors.NewGenericOSPath(self.temp_file)
|
||||
assert.NoError(self.T(), err)
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) TearDownTest() {
|
||||
self.cancel()
|
||||
self.wg.Wait()
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) truncateFile() {
|
||||
fd, err := os.OpenFile(self.temp_file,
|
||||
os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
assert.NoError(self.T(), err)
|
||||
fd.Close()
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) appendData(data string) {
|
||||
fd, err := os.OpenFile(self.temp_file,
|
||||
os.O_RDWR|os.O_CREATE, 0600)
|
||||
assert.NoError(self.T(), err)
|
||||
defer fd.Close()
|
||||
|
||||
fd.Seek(0, os.SEEK_END)
|
||||
|
||||
_, err = fd.Write([]byte(data))
|
||||
assert.NoError(self.T(), err)
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) clearLines() {
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
self.result = nil
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) getLines() []vfilter.Row {
|
||||
self.mu.Lock()
|
||||
defer self.mu.Unlock()
|
||||
result := []vfilter.Row{}
|
||||
for _, i := range self.result {
|
||||
result = append(result, i)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (self *SyslogWatcherTestSuite) TestSyslogReader() {
|
||||
service := NewSyslogWatcherService(self.ConfigObj)
|
||||
|
||||
golden := ordereddict.NewDict()
|
||||
|
||||
// Register a watcher
|
||||
accessor, err := accessors.GetAccessor("file", self.scope)
|
||||
assert.NoError(self.T(), err)
|
||||
|
||||
ctx := context.Background()
|
||||
closer := service.Register(self.filename, "file",
|
||||
ctx, self.scope, self.output_chan)
|
||||
defer closer()
|
||||
|
||||
// Registering a watcher will scan the file once. We need to wait
|
||||
// until it is over before we start the test.
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
service.mu.Lock()
|
||||
defer service.mu.Unlock()
|
||||
|
||||
return service.monitor_count > 0
|
||||
})
|
||||
|
||||
// Find the last line
|
||||
cursor := service.findLastLineOffset(self.filename, accessor)
|
||||
assert.Equal(self.T(), cursor.last_line_offset, int64(0))
|
||||
|
||||
self.appendData("This is the first line\nSecond Line\n")
|
||||
|
||||
// Find the last line again
|
||||
cursor = service.findLastLineOffset(self.filename, accessor)
|
||||
assert.Equal(self.T(), cursor.last_line_offset, int64(35))
|
||||
assert.Equal(self.T(), cursor.file_size, int64(35))
|
||||
|
||||
// Pull the next line off - no new data
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
assert.Equal(self.T(), cursor.last_line_offset, int64(35))
|
||||
|
||||
// Write 3 short full lines (10 bytes + \n * 3 = 33 bytes). This
|
||||
// should fit in a single buffer read (50 bytes)
|
||||
self.appendData("0123456701\n0123456702\n0123456703\n")
|
||||
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
|
||||
// Make sure we consumed all the data since it ends on \n
|
||||
assert.Equal(self.T(), cursor.last_line_offset, cursor.file_size)
|
||||
|
||||
// Wait for 3 messages to be distributed
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
return len(self.getLines()) == 3
|
||||
})
|
||||
|
||||
golden.Set("Short Lines", self.getLines())
|
||||
|
||||
self.clearLines()
|
||||
|
||||
// Write 3 longer full lines (20 bytes + \n * 3 = 63 bytes). While
|
||||
// each line should fit in the buffer (50 bytes) the whole data
|
||||
// since the last cursor will not at once.
|
||||
self.appendData("01234567890123456701\n01234567890123456702\n01234567890123456703\n")
|
||||
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
assert.Equal(self.T(), cursor.last_line_offset, cursor.file_size)
|
||||
|
||||
// Wait for 3 messages to be distributed
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
return len(self.getLines()) == 3
|
||||
})
|
||||
|
||||
golden.Set("Long Lines", self.getLines())
|
||||
|
||||
// Write data with no crlf should not advance cursor.
|
||||
// each line should fit in the buffer (50 bytes) the whole data
|
||||
// since the last cursor will not at once.
|
||||
self.appendData("0123456no crlf")
|
||||
|
||||
self.clearLines()
|
||||
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
|
||||
// Cursor has not consumed the last line because there is no \n
|
||||
assert.True(self.T(), cursor.last_line_offset < cursor.file_size)
|
||||
|
||||
self.appendData("and this is crlf\n")
|
||||
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
|
||||
// All data is consumed
|
||||
assert.Equal(self.T(), cursor.last_line_offset, cursor.file_size)
|
||||
|
||||
// Wait for 3 messages to be distributed
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
return len(self.getLines()) == 1
|
||||
})
|
||||
|
||||
golden.Set("Broken Line", self.getLines())
|
||||
|
||||
self.clearLines()
|
||||
|
||||
// Now send a single line which is too long to fit in the
|
||||
// buffer. Total length 63 bytes
|
||||
self.appendData("01234567890123456701,01234567890123456702,01234567890123456703\n")
|
||||
|
||||
// We still read all the way to the end but we split the data over
|
||||
// multiple lines.
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
assert.Equal(self.T(), cursor.last_line_offset, cursor.file_size)
|
||||
|
||||
// Message is broken across multiple lines because it is too long
|
||||
// to fit in one buffer.
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
return len(self.getLines()) == 2
|
||||
})
|
||||
|
||||
golden.Set("Broken Buffer", self.getLines())
|
||||
|
||||
// Now test file truncation.
|
||||
self.truncateFile()
|
||||
self.clearLines()
|
||||
|
||||
// Write 3 short full lines (10 bytes + \n * 3 = 33 bytes). This
|
||||
// should fit in a single buffer read (50 bytes)
|
||||
self.appendData("0123456701\n0123456702\n0123456703\n")
|
||||
|
||||
// The new curser is rewinded to the start of the file.
|
||||
old_curser := *cursor
|
||||
new_cursor := service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
|
||||
assert.True(self.T(), new_cursor.last_line_offset < old_curser.last_line_offset)
|
||||
assert.Equal(self.T(), new_cursor.last_line_offset, new_cursor.file_size)
|
||||
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
return len(self.getLines()) == 3
|
||||
})
|
||||
|
||||
golden.Set("Lines after file rewind", self.getLines())
|
||||
|
||||
self.clearLines()
|
||||
|
||||
// Now write empty lines.
|
||||
self.appendData("\n\n\n")
|
||||
|
||||
// Lines are consumed
|
||||
cursor = service.monitorOnce(self.filename, "file", accessor, cursor)
|
||||
assert.Equal(self.T(), cursor.last_line_offset, cursor.file_size)
|
||||
|
||||
vtesting.WaitUntil(time.Second, self.T(), func() bool {
|
||||
return len(self.getLines()) == 3
|
||||
})
|
||||
|
||||
golden.Set("Empty lines", self.getLines())
|
||||
|
||||
goldie.Assert(self.T(), "TestSyslogReader",
|
||||
json.MustMarshalIndent(golden))
|
||||
}
|
||||
|
||||
func TestSyslogWatcher(t *testing.T) {
|
||||
suite.Run(t, &SyslogWatcherTestSuite{})
|
||||
}
|
||||
Reference in New Issue
Block a user