From 3c068df6847bc6d668de0519e9d2994b89030dff Mon Sep 17 00:00:00 2001 From: Michael Cohen Date: Mon, 7 Jan 2019 16:08:57 +0000 Subject: [PATCH] Better windows service installer. --- Makefile | 3 + actions/events.go | 6 +- actions/files_darwin.go | 30 -- actions/files_linux.go | 30 -- actions/files_windows.go | 10 - actions/vql.go | 6 +- api/api.go | 6 +- api/artifacts.go | 4 +- api/auth.go | 2 +- api/clients.go | 6 +- api/oauth.go | 16 +- api/proto/config.pb.go | 391 ++++++++++---------- api/proto/config.proto | 4 + api/vfs.go | 3 + artifacts/artifacts.go | 8 +- artifacts/plugin.go | 4 +- bin/artifacts.go | 13 +- bin/artifacts_acquire.go | 3 + bin/artifacts_hunt.go | 12 + bin/config.go | 10 +- bin/installer_windows.go | 42 ++- bin/pool.go | 5 +- bin/repack.go | 5 +- bin/shell.go | 1 - bin/utils.go | 15 - bin/version.go | 2 +- bin/vql.go | 2 +- config/config.go | 2 +- datastore/datastore.go | 2 +- datastore/filebased.go | 2 +- file_store/csv/reader.go | 5 +- file_store/csv/reader_test.go | 27 -- file_store/csv/utils.go | 2 +- file_store/csv/writer.go | 2 +- file_store/file_store.go | 6 +- flows/artifacts.go | 4 + flows/events.go | 13 +- flows/file_finder.go | 19 +- flows/fixtures/compileFileFinderArgs.golden | 4 +- flows/foreman.go | 11 +- flows/generic.go | 2 +- flows/hunts.go | 4 + flows/interrogate.go | 15 +- flows/utils.go | 3 + glob/accessor_linux.go | 29 +- glob/factory.go | 3 +- glob/glob.go | 5 +- http_comms/comms.go | 27 +- server/comms.go | 11 +- server/flows.go | 2 +- server/server.go | 25 +- services/hunt_dispatcher.go | 4 +- services/{hunts.go => hunt_manager.go} | 7 +- staticcheck.conf | 6 + vql/binary.go | 17 +- vql/common/yara.go | 16 +- vql/filesystem/path.go | 2 +- vql/filesystem/tempfile.go | 4 - vql/functions/functions.go | 1 + vql/linux/users.go | 9 +- vql/networking/uploader.go | 6 +- vql/parsers/evtx.go | 14 +- vql/parsers/json.go | 2 +- vql/parsers/splitparser.go | 2 +- vql/scope.go | 3 +- vql/server/monitoring.go | 1 - vql/windows/filesystems/os_windows.go | 21 +- 67 files changed, 439 insertions(+), 540 deletions(-) delete mode 100644 actions/files_darwin.go delete mode 100644 actions/files_linux.go delete mode 100644 actions/files_windows.go rename services/{hunts.go => hunt_manager.go} (97%) create mode 100644 staticcheck.conf diff --git a/Makefile b/Makefile index 9d6f76b1cd6..61c76801469 100644 --- a/Makefile +++ b/Makefile @@ -21,3 +21,6 @@ clean: generate: go generate ./vql/windows/win32_windows.go + +check: + staticcheck ./... diff --git a/actions/events.go b/actions/events.go index dcf1db47c37..abeb0378d14 100644 --- a/actions/events.go +++ b/actions/events.go @@ -37,10 +37,8 @@ func (self *UpdateEventTable) Run( // Cancel the context when the cancel channel is closed. go func() { - select { - case <-table.Done: - cancel() - } + <-table.Done + cancel() }() logger := logging.GetLogger(config, &logging.ClientComponent) diff --git a/actions/files_darwin.go b/actions/files_darwin.go deleted file mode 100644 index 920f5378357..00000000000 --- a/actions/files_darwin.go +++ /dev/null @@ -1,30 +0,0 @@ -package actions - -import ( - "os" - "syscall" - actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" -) - -func buildStatEntryFromFileInfo(stat os.FileInfo) *actions_proto.StatEntry { - sys_stat, ok := stat.Sys().(*syscall.Stat_t) - if ok { - stat_reply := &actions_proto.StatEntry{ - StMode: uint64(sys_stat.Mode), - StIno: uint32(sys_stat.Ino), - StDev: uint32(sys_stat.Dev), - StNlink: uint32(sys_stat.Nlink), - StUid: sys_stat.Uid, - StGid: sys_stat.Gid, - StSize: uint64(sys_stat.Size), - StAtime: uint64(sys_stat.Atimespec.Sec), - StMtime: uint64(sys_stat.Mtimespec.Sec), - StCtime: uint64(sys_stat.Ctimespec.Sec), - StBlocks: uint32(sys_stat.Blocks), - StBlksize: uint32(sys_stat.Blksize), - } - return stat_reply - } - - return nil -} diff --git a/actions/files_linux.go b/actions/files_linux.go deleted file mode 100644 index 31229005a12..00000000000 --- a/actions/files_linux.go +++ /dev/null @@ -1,30 +0,0 @@ -package actions - -import ( - "os" - "syscall" - actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" -) - -func buildStatEntryFromFileInfo(stat os.FileInfo) *actions_proto.StatEntry { - sys_stat, ok := stat.Sys().(*syscall.Stat_t) - if ok { - stat_reply := &actions_proto.StatEntry{ - StMode: uint64(sys_stat.Mode), - StIno: uint32(sys_stat.Ino), - StDev: uint32(sys_stat.Dev), - StNlink: uint32(sys_stat.Nlink), - StUid: sys_stat.Uid, - StGid: sys_stat.Gid, - StSize: uint64(sys_stat.Size), - StAtime: uint64(sys_stat.Atim.Sec), - StMtime: uint64(sys_stat.Mtim.Sec), - StCtime: uint64(sys_stat.Ctim.Sec), - StBlocks: uint32(sys_stat.Blocks), - StBlksize: uint32(sys_stat.Blksize), - } - return stat_reply - } - - return nil -} diff --git a/actions/files_windows.go b/actions/files_windows.go deleted file mode 100644 index 83ddff13f12..00000000000 --- a/actions/files_windows.go +++ /dev/null @@ -1,10 +0,0 @@ -package actions - -import ( - "os" - actions_proto "www.velocidex.com/golang/velociraptor/actions/proto" -) - -func buildStatEntryFromFileInfo(stat os.FileInfo) *actions_proto.StatEntry { - return nil -} diff --git a/actions/vql.go b/actions/vql.go index 843ba8cc989..34b7357f1f1 100644 --- a/actions/vql.go +++ b/actions/vql.go @@ -64,8 +64,10 @@ func (self *VQLClientAction) StartQuery( rate = 1000000 } - throttle := time.Tick(time.Nanosecond * + ticker := time.NewTicker(time.Nanosecond * time.Duration((float64(1000000000) / float64(rate)))) + defer ticker.Stop() + if arg.Query == nil { responder.RaiseError("Query should be specified.") return @@ -90,7 +92,7 @@ func (self *VQLClientAction) StartQuery( Set("$responder", responder). Set("$uploader", uploader). Set("config", config_obj). - Set("$throttle", throttle). + Set("$throttle", ticker.C). Set(vql_subsystem.CACHE_VAR, vql_subsystem.NewScopeCache()) for _, env_spec := range arg.Env { diff --git a/api/api.go b/api/api.go index 18f043247ac..ed7911395a1 100644 --- a/api/api.go +++ b/api/api.go @@ -189,13 +189,13 @@ func (self *ApiServer) NotifyClients( ctx context.Context, in *api_proto.NotificationRequest) (*empty.Empty, error) { if in.NotifyAll { - self.server_obj.Info("Sending notification to everyone") + self.server_obj.Info("sending notification to everyone") self.server_obj.NotificationPool.NotifyAll() } else if in.ClientId != "" { - self.server_obj.Info("Sending notification to %s", in.ClientId) + self.server_obj.Info("sending notification to %s", in.ClientId) self.server_obj.NotificationPool.Notify(in.ClientId) } else { - return nil, errors.New("Client id should be specified.") + return nil, errors.New("client id should be specified") } return &empty.Empty{}, nil } diff --git a/api/artifacts.go b/api/artifacts.go index 3822d83e28a..a662d46e7c9 100644 --- a/api/artifacts.go +++ b/api/artifacts.go @@ -63,11 +63,11 @@ func setArtifactFile(config_obj *api_proto.Config, vfs_path = path.Clean(vfs_path) if vfs_path == "" || !strings.HasSuffix(vfs_path, ".yaml") { - return errors.New("Artifact filename must end with .yaml") + return errors.New("artifact filename must end with .yaml") } if !strings.HasPrefix(vfs_path, constants.ARTIFACT_DEFINITION) { - return errors.New("Artifacts may only be stored in " + + return errors.New("artifacts may only be stored in " + constants.ARTIFACT_DEFINITION) } diff --git a/api/auth.go b/api/auth.go index 1f94e42031c..767c555f6c2 100644 --- a/api/auth.go +++ b/api/auth.go @@ -29,7 +29,7 @@ func checkUserCredentialsHandler( w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) username, password, ok := r.BasicAuth() - if ok == false { + if !ok { http.Error(w, "Not authorized", http.StatusUnauthorized) return } diff --git a/api/clients.go b/api/clients.go index 4b0c497993e..8760871da12 100644 --- a/api/clients.go +++ b/api/clients.go @@ -17,7 +17,7 @@ func GetApiClient( *api_proto.ApiClient, error) { if client_id[0] != 'C' { - return nil, errors.New("Client_id must start with C") + return nil, errors.New("client_id must start with C") } result := &api_proto.ApiClient{ @@ -62,9 +62,7 @@ func GetApiClient( } if client_info.Knowledgebase != nil { - for _, user := range client_info.Knowledgebase.Users { - result.Users = append(result.Users, user) - } + result.Users = append(result.Users, client_info.Knowledgebase.Users...) } err = db.GetSubject( diff --git a/api/oauth.go b/api/oauth.go index 4eaf86e6abb..74138e2698c 100644 --- a/api/oauth.go +++ b/api/oauth.go @@ -100,6 +100,11 @@ func oauthGoogleCallback(config_obj *api_proto.Config) http.Handler { // Sign and get the complete encoded token as a string using the secret tokenString, err := token.SignedString( []byte(config_obj.Frontend.PrivateKey)) + if err != nil { + log.Println(err.Error()) + http.Redirect(w, r, "/", http.StatusTemporaryRedirect) + return + } // Set the cookie and redirect. cookie := &http.Cookie{ @@ -148,7 +153,6 @@ func authenticateOAUTHCookie( // Not authorized - redirect to logon screen. http.Redirect(w, r, "/auth/google/login", http.StatusTemporaryRedirect) - return } auth_cookie, err := r.Cookie("VelociraptorAuth") @@ -163,7 +167,7 @@ func authenticateOAUTHCookie( func(token *jwt.Token) (interface{}, error) { _, ok := token.Method.(*jwt.SigningMethodHMAC) if !ok { - return nil, errors.New("Invalid signing method") + return nil, errors.New("invalid signing method") } return []byte(config_obj.Frontend.PrivateKey), nil }) @@ -174,7 +178,7 @@ func authenticateOAUTHCookie( claims, ok := token.Claims.(jwt.MapClaims) if !ok || !token.Valid { - reject(errors.New("Token not valid")) + reject(errors.New("token not valid")) return } @@ -182,19 +186,19 @@ func authenticateOAUTHCookie( // stack. username, pres := claims["user"].(string) if !pres { - reject(errors.New("Username not present")) + reject(errors.New("username not present")) return } // Check if the claim is too old. expires, pres := claims["expires"].(float64) if !pres { - reject(errors.New("Expires field not present in JWT")) + reject(errors.New("expires field not present in JWT")) return } if expires < float64(time.Now().Unix()) { - reject(errors.New("JWT expired - reauthenticate.")) + reject(errors.New("the JWT is expired - reauthenticate")) return } diff --git a/api/proto/config.pb.go b/api/proto/config.pb.go index bbd5ad892c3..6bdc55957d4 100644 --- a/api/proto/config.pb.go +++ b/api/proto/config.pb.go @@ -564,6 +564,7 @@ type FrontendConfig struct { ClientLeaseTime uint32 `protobuf:"varint,5,opt,name=client_lease_time,json=clientLeaseTime,proto3" json:"client_lease_time,omitempty"` DnsName string `protobuf:"bytes,6,opt,name=dns_name,json=dnsName,proto3" json:"dns_name,omitempty"` ArtifactsPath string `protobuf:"bytes,7,opt,name=artifacts_path,json=artifactsPath,proto3" json:"artifacts_path,omitempty"` + PublicPath string `protobuf:"bytes,8,opt,name=public_path,json=publicPath,proto3" json:"public_path,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -643,6 +644,13 @@ func (m *FrontendConfig) GetArtifactsPath() string { return "" } +func (m *FrontendConfig) GetPublicPath() string { + if m != nil { + return m.PublicPath + } + return "" +} + type DatastoreConfig struct { Implementation string `protobuf:"bytes,1,opt,name=implementation,proto3" json:"implementation,omitempty"` Location string `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` @@ -1077,198 +1085,201 @@ func init() { func init() { proto.RegisterFile("config.proto", fileDescriptor_3eaf2c85e69e9ea4) } var fileDescriptor_3eaf2c85e69e9ea4 = []byte{ - // 3079 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x59, 0xc9, 0x73, 0x5c, 0xc7, - 0x79, 0xaf, 0x01, 0x48, 0x2c, 0x3d, 0x58, 0x88, 0xe6, 0x36, 0xa2, 0x48, 0xb1, 0x35, 0x5a, 0x08, - 0x2a, 0xcc, 0xc3, 0x42, 0x8a, 0x92, 0x28, 0x29, 0xe4, 0x60, 0x21, 0x05, 0x11, 0xa4, 0xc0, 0x47, - 0x80, 0x4c, 0x29, 0x4a, 0x4d, 0x7a, 0xde, 0xeb, 0x99, 0x69, 0xf1, 0x4d, 0xf7, 0x53, 0x77, 0x3f, - 0x0c, 0x90, 0x54, 0xa5, 0x92, 0x9c, 0xa4, 0xe4, 0x96, 0x43, 0xb6, 0xaa, 0x54, 0x4a, 0x8a, 0x7d, - 0xd3, 0x41, 0x77, 0x5f, 0x7d, 0xf0, 0x5f, 0xe1, 0x83, 0x7d, 0xf1, 0xc5, 0x55, 0xf2, 0xc9, 0x17, - 0x1f, 0x5c, 0xfd, 0x75, 0xbf, 0x65, 0x40, 0xb8, 0x64, 0xbb, 0x74, 0xf0, 0xc1, 0x97, 0x01, 0xa6, - 0xfb, 0xfb, 0x7e, 0xdf, 0xf7, 0x75, 0x7f, 0x6b, 0x0f, 0x9a, 0x89, 0xa4, 0xe8, 0xf2, 0x5e, 0x90, - 0x2a, 0x69, 0x24, 0x3e, 0x09, 0x7f, 0x2e, 0xdc, 0x1a, 0x0e, 0x87, 0xc1, 0x3e, 0x4b, 0x64, 0xc4, - 0x63, 0x76, 0x10, 0x44, 0x72, 0xb0, 0xd4, 0x93, 0x09, 0x15, 0xbd, 0x25, 0xb7, 0xa8, 0x68, 0x6a, - 0xa4, 0x5a, 0x02, 0xe2, 0x25, 0xcd, 0x06, 0x54, 0x18, 0x1e, 0x39, 0x88, 0x0b, 0xef, 0xff, 0x7e, - 0xbc, 0x34, 0x32, 0x5c, 0x0a, 0xed, 0x31, 0xf6, 0x3f, 0x4b, 0x1c, 0x7b, 0xf3, 0xdb, 0x31, 0x34, - 0xf9, 0x84, 0x29, 0xcd, 0xa5, 0xc0, 0x01, 0x3a, 0x21, 0xe8, 0x80, 0x35, 0x6a, 0xa4, 0xb6, 0x38, - 0xbd, 0x76, 0xe1, 0x67, 0xbf, 0xf9, 0xf9, 0x8f, 0x6b, 0x67, 0x30, 0xde, 0xed, 0x33, 0x12, 0x25, - 0x9c, 0x09, 0x73, 0x45, 0x13, 0x4b, 0x10, 0x84, 0x40, 0x87, 0x1f, 0xa2, 0x7a, 0xcc, 0x74, 0xa4, - 0x78, 0x6a, 0xb1, 0x1b, 0x63, 0xc0, 0x76, 0x0d, 0xd8, 0x5e, 0xc7, 0xaf, 0x8e, 0xb0, 0x25, 0x52, - 0xf4, 0x48, 0x85, 0x98, 0x68, 0xa3, 0xb8, 0xe8, 0x85, 0x55, 0x00, 0x4c, 0xd1, 0xe4, 0xbe, 0x53, - 0xa5, 0x31, 0x0e, 0x58, 0xf7, 0x00, 0xab, 0x85, 0x6f, 0x8f, 0x60, 0x79, 0x1a, 0x0f, 0x41, 0x32, - 0x6d, 0x3f, 0x29, 0xc9, 0xcf, 0x25, 0xdf, 0xb7, 0xab, 0x3a, 0xea, 0x33, 0xab, 0x6f, 0x8e, 0x8b, + // 3132 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x59, 0xb9, 0x73, 0x5c, 0x47, + 0x7a, 0xaf, 0x01, 0x48, 0x1c, 0x3d, 0x38, 0x88, 0xe6, 0x35, 0xa2, 0x48, 0xb1, 0x35, 0x3a, 0x08, + 0xca, 0xf4, 0xc3, 0x41, 0x8a, 0x92, 0xa8, 0x83, 0x1c, 0x1c, 0xa4, 0x20, 0x82, 0x14, 0xf8, 0x08, + 0x90, 0x2e, 0x59, 0xae, 0x71, 0xcf, 0x7b, 0x3d, 0x33, 0x2d, 0xbe, 0xe9, 0x7e, 0xea, 0xee, 0x87, + 0x01, 0xec, 0x2a, 0x97, 0xed, 0x48, 0xb2, 0x33, 0x07, 0xbe, 0xaa, 0x5c, 0x2e, 0xc9, 0x76, 0xa6, + 0x40, 0xb9, 0xd3, 0x0d, 0xf6, 0x6f, 0xd8, 0x60, 0x83, 0xdd, 0x64, 0x93, 0xad, 0x52, 0xb6, 0xc9, + 0x06, 0x5b, 0xfd, 0x75, 0xbf, 0x63, 0x40, 0x6c, 0x69, 0x77, 0x4b, 0xc1, 0x06, 0x9b, 0x80, 0x44, + 0xbf, 0xef, 0xfb, 0x7d, 0xdf, 0xd7, 0xfd, 0xdd, 0x40, 0x33, 0x91, 0x14, 0x5d, 0xde, 0x0b, 0x52, + 0x25, 0x8d, 0xc4, 0x27, 0xe1, 0x9f, 0x0b, 0xb7, 0x86, 0xc3, 0x61, 0xb0, 0xcf, 0x12, 0x19, 0xf1, + 0x98, 0x1d, 0x04, 0x91, 0x1c, 0x2c, 0xf5, 0x64, 0x42, 0x45, 0x6f, 0xc9, 0x1d, 0x2a, 0x9a, 0x1a, + 0xa9, 0x96, 0x80, 0x78, 0x49, 0xb3, 0x01, 0x15, 0x86, 0x47, 0x0e, 0xe2, 0xc2, 0xfb, 0xbf, 0x1b, + 0x2f, 0x8d, 0x0c, 0x97, 0x42, 0x7b, 0x8c, 0xfd, 0xcf, 0x13, 0xc7, 0xde, 0xfc, 0x6e, 0x0c, 0x4d, + 0x3e, 0x61, 0x4a, 0x73, 0x29, 0x70, 0x80, 0x4e, 0x08, 0x3a, 0x60, 0x8d, 0x1a, 0xa9, 0x2d, 0x4e, + 0xaf, 0x5d, 0xf8, 0xd9, 0xaf, 0x7f, 0xfe, 0xa3, 0xda, 0x19, 0x8c, 0x77, 0xfb, 0x8c, 0x44, 0x09, + 0x67, 0xc2, 0x5c, 0xd1, 0xc4, 0x12, 0x04, 0x21, 0xd0, 0xe1, 0x87, 0xa8, 0x1e, 0x33, 0x1d, 0x29, + 0x9e, 0x5a, 0xec, 0xc6, 0x18, 0xb0, 0x5d, 0x03, 0xb6, 0xd7, 0xf1, 0xab, 0x23, 0x6c, 0x89, 0x14, + 0x3d, 0x52, 0x21, 0x26, 0xda, 0x28, 0x2e, 0x7a, 0x61, 0x15, 0x00, 0x53, 0x34, 0xb9, 0xef, 0x54, + 0x69, 0x8c, 0x03, 0xd6, 0x3d, 0xc0, 0x6a, 0xe1, 0xdb, 0x23, 0x58, 0x9e, 0xc6, 0x43, 0x90, 0x4c, + 0xdb, 0x9f, 0x94, 0xe4, 0xf7, 0x92, 0x7f, 0xb7, 0xa7, 0x3a, 0xea, 0x33, 0xab, 0x6f, 0x8e, 0x8b, 0x6f, 0xa3, 0x89, 0x48, 0x0e, 0x06, 0xdc, 0x34, 0x4e, 0x80, 0x84, 0x2b, 0x20, 0xe1, 0x65, 0x7c, 0x79, 0x44, 0x42, 0x8f, 0x1b, 0xe2, 0xc8, 0xbc, 0x90, 0x20, 0xf4, 0x6c, 0xb8, 0x85, 0x50, 0x27, 0xe3, 0x49, 0xdc, 0x36, 0x7c, 0xc0, 0x1a, 0x27, 0x01, 0xa4, 0x09, 0x20, 0x17, 0xf1, 0x85, 0xa7, 0x7d, 0x26, 0x88, 0x29, 0x90, 0xc8, 0x90, 0x6a, 0x62, 0xa9, 0x4d, 0x10, 0x4e, 0x03, 0xd7, 0x2e, - 0x1f, 0xb0, 0xe6, 0xd7, 0xe3, 0x68, 0xfa, 0xa9, 0xe2, 0x86, 0x75, 0x68, 0xf4, 0x0c, 0x87, 0xa8, - 0x9e, 0x2a, 0xbe, 0x4f, 0x0d, 0x6b, 0x3f, 0x63, 0x87, 0x8d, 0x49, 0x40, 0x5c, 0x01, 0xc4, 0xbf, - 0xc0, 0x57, 0x47, 0xd4, 0xf2, 0x74, 0xe4, 0x19, 0x3b, 0x24, 0x5c, 0x90, 0x9d, 0xcd, 0x07, 0x84, - 0x89, 0x48, 0xc6, 0xa0, 0x20, 0xf2, 0xbb, 0xf7, 0xd9, 0x21, 0xfe, 0x3b, 0x74, 0xba, 0x9f, 0x09, - 0xd3, 0x4e, 0xa8, 0x36, 0xa0, 0xa8, 0x36, 0x74, 0x90, 0x36, 0x66, 0x49, 0x6d, 0xf1, 0xc4, 0xda, - 0x32, 0x60, 0xbf, 0x81, 0x17, 0x2d, 0xb6, 0xa5, 0x20, 0x96, 0x96, 0x14, 0x64, 0xc4, 0xf4, 0xb9, - 0xce, 0x2d, 0x50, 0x54, 0x04, 0xe1, 0x82, 0x25, 0xd8, 0xa6, 0xda, 0xec, 0xe6, 0x34, 0xf8, 0x17, - 0x35, 0xf4, 0x02, 0xa0, 0x6b, 0xa6, 0xf6, 0x99, 0xb2, 0x7f, 0x38, 0x4d, 0xda, 0x22, 0x1b, 0x74, - 0x98, 0x6a, 0xcc, 0x81, 0xa0, 0xaf, 0x6b, 0x20, 0xe9, 0x87, 0x35, 0xfc, 0x55, 0xad, 0x90, 0x15, - 0x31, 0x65, 0x78, 0x97, 0x47, 0xd6, 0x0e, 0xc7, 0x44, 0x1c, 0x13, 0x19, 0x32, 0xa2, 0xe9, 0x90, - 0x74, 0x95, 0x1c, 0xc0, 0x19, 0x3a, 0xe4, 0x80, 0xac, 0x83, 0x26, 0x9a, 0x28, 0xd6, 0xcd, 0x34, - 0x23, 0x46, 0x92, 0x48, 0x0a, 0xc1, 0x22, 0x63, 0xff, 0x75, 0x44, 0x9a, 0x0c, 0xb9, 0xe9, 0x13, - 0x99, 0xc4, 0x4c, 0x8d, 0xa2, 0x6a, 0x42, 0x35, 0x49, 0xa9, 0x32, 0x44, 0x76, 0x3d, 0x31, 0x1c, - 0x9f, 0x92, 0x86, 0x82, 0x1f, 0x42, 0x14, 0x44, 0x32, 0x09, 0xc2, 0x73, 0x56, 0xbf, 0xc7, 0x40, - 0xf2, 0x18, 0x20, 0x1e, 0x02, 0x42, 0xf3, 0xdf, 0xc6, 0xd0, 0xb9, 0xa7, 0x5c, 0xc4, 0x72, 0xa8, - 0xb7, 0x84, 0x36, 0x34, 0x49, 0x98, 0x5a, 0x87, 0x20, 0xc6, 0x0f, 0xd0, 0x8c, 0xc5, 0xe4, 0x11, - 0x6b, 0x57, 0x02, 0xe7, 0x0d, 0x30, 0xfb, 0x55, 0xdc, 0xb4, 0x46, 0xdb, 0x75, 0x2b, 0x3b, 0xb7, - 0x88, 0x47, 0xce, 0x04, 0xc5, 0xa8, 0x61, 0x41, 0x58, 0xf7, 0x6b, 0x0f, 0x6d, 0x3c, 0x7d, 0x59, - 0x43, 0x33, 0xdc, 0x89, 0x68, 0xa7, 0xd4, 0xf4, 0x7d, 0x44, 0xfd, 0x23, 0xe0, 0x1d, 0xe0, 0xfd, - 0xa7, 0x7d, 0xa6, 0x18, 0xd1, 0x7d, 0x99, 0x25, 0x31, 0x00, 0x76, 0xb8, 0xa0, 0xea, 0x90, 0x74, - 0x18, 0xf1, 0x6c, 0x2c, 0xbe, 0x4d, 0xac, 0x54, 0xff, 0x15, 0x9c, 0x98, 0x8a, 0x98, 0x44, 0x32, - 0xe5, 0x4c, 0x57, 0x79, 0x8c, 0x74, 0xf7, 0x9c, 0xc8, 0xc8, 0x1d, 0x84, 0x25, 0xf3, 0x6c, 0xba, - 0xaa, 0x6d, 0x10, 0xd6, 0xfd, 0xf2, 0x0e, 0x35, 0xfd, 0xe6, 0xbf, 0x8e, 0xa1, 0xb3, 0x1b, 0x54, - 0x0d, 0xb9, 0xf8, 0xf3, 0x61, 0x34, 0x3f, 0x9f, 0x41, 0x33, 0xce, 0x3d, 0xfd, 0x19, 0xfc, 0x73, - 0x0d, 0x4d, 0x24, 0xb4, 0xc3, 0x12, 0xdd, 0x98, 0x20, 0xe3, 0x8b, 0xd3, 0x6b, 0x1c, 0xd4, 0x8d, - 0x30, 0x6d, 0x91, 0x84, 0x6b, 0xf0, 0x42, 0xb7, 0x5f, 0x4d, 0x13, 0x7d, 0xaa, 0x03, 0xb2, 0x6b, - 0x15, 0xa0, 0x49, 0x22, 0x87, 0x9a, 0x68, 0x96, 0xb0, 0xc8, 0xb0, 0x98, 0xf4, 0x94, 0xcc, 0x52, - 0x6d, 0xb9, 0x22, 0x1f, 0x05, 0x46, 0x5a, 0x0b, 0x0d, 0x55, 0x3d, 0x66, 0x2c, 0x05, 0x17, 0x10, - 0xbe, 0x3a, 0x08, 0xbd, 0x60, 0x4c, 0x51, 0xdd, 0x07, 0x65, 0xa6, 0x12, 0xdd, 0x98, 0x02, 0x3d, - 0xee, 0x80, 0x1e, 0xb7, 0xf0, 0xdb, 0xa5, 0x1e, 0x3e, 0x1a, 0xf6, 0xc2, 0xed, 0x11, 0x65, 0x86, - 0x3c, 0x49, 0x88, 0x71, 0x87, 0x52, 0x06, 0x5a, 0x10, 0x22, 0x47, 0xbf, 0xa7, 0x12, 0x8d, 0xbf, - 0xa8, 0xa1, 0xb9, 0x88, 0xb6, 0x2b, 0xb1, 0xdc, 0xa8, 0xc3, 0xed, 0x74, 0x40, 0xcc, 0x27, 0xf8, - 0x63, 0x7b, 0xee, 0xeb, 0xad, 0x2b, 0x7a, 0x24, 0xde, 0x21, 0x59, 0x39, 0x9d, 0x77, 0x36, 0x1f, - 0x04, 0x64, 0xf7, 0x39, 0xa9, 0x99, 0x36, 0x84, 0x8a, 0xc3, 0x5c, 0x37, 0xcd, 0x7b, 0x82, 0xc5, - 0x2e, 0xb8, 0xe1, 0x82, 0xd6, 0x5b, 0x41, 0x38, 0x1b, 0xd1, 0xf5, 0x12, 0x14, 0xff, 0xa8, 0x86, - 0x4e, 0x0a, 0x29, 0x22, 0xd6, 0x98, 0x01, 0x15, 0x7e, 0xe0, 0xb2, 0xce, 0xff, 0xd6, 0xf0, 0xff, - 0xd4, 0x5a, 0x44, 0xf7, 0xa9, 0x62, 0x31, 0x01, 0x82, 0xe7, 0xac, 0x4c, 0x15, 0xd3, 0x4c, 0x18, - 0xa7, 0x88, 0x17, 0x09, 0x1b, 0x8a, 0x7d, 0x6a, 0xcd, 0xce, 0xcf, 0x7c, 0xd8, 0xe7, 0x51, 0x9f, - 0xc4, 0x92, 0x08, 0x69, 0x72, 0x26, 0xa7, 0x8f, 0x4d, 0x25, 0x5a, 0x12, 0x6e, 0xc8, 0xc0, 0xaa, - 0xde, 0x61, 0x84, 0x0d, 0x3a, 0x2c, 0xf6, 0x46, 0x9a, 0x6a, 0xf2, 0x76, 0x75, 0x3f, 0x53, 0xe0, - 0x60, 0x41, 0xe8, 0x74, 0xc6, 0x5d, 0x74, 0x6a, 0x98, 0x97, 0x82, 0x76, 0x0c, 0x71, 0xd5, 0x38, - 0x03, 0x76, 0xbc, 0x0b, 0x66, 0xbc, 0x89, 0xaf, 0xb7, 0x88, 0x75, 0x7f, 0x32, 0x04, 0x7f, 0x77, - 0x24, 0xa5, 0x66, 0x56, 0x5b, 0x00, 0x00, 0xdf, 0x4d, 0x88, 0x36, 0x10, 0x49, 0xf3, 0x05, 0xa8, - 0x8b, 0x55, 0x1c, 0xa1, 0x72, 0xa9, 0x9d, 0x70, 0x91, 0x1d, 0x34, 0xa6, 0x41, 0xcc, 0x2d, 0x10, - 0x73, 0x03, 0xaf, 0x8e, 0x88, 0x01, 0x8a, 0xef, 0x94, 0x32, 0x57, 0x40, 0x6e, 0x5b, 0x7a, 0xcc, - 0xd1, 0x42, 0x29, 0x64, 0xe8, 0x52, 0x66, 0x03, 0x81, 0x98, 0xf7, 0x40, 0xcc, 0x4d, 0x7c, 0x63, - 0x44, 0x8c, 0xa7, 0xf9, 0x4e, 0x41, 0xe5, 0x19, 0xf9, 0x44, 0x8c, 0xff, 0x06, 0x4d, 0x0d, 0xe8, - 0x41, 0x3b, 0x95, 0x49, 0xd2, 0x98, 0x87, 0x6a, 0x93, 0x7b, 0xf8, 0x75, 0x7b, 0x99, 0x03, 0x7a, - 0xc0, 0x07, 0xd9, 0x20, 0x2f, 0x2d, 0xe0, 0xed, 0x91, 0x14, 0xb1, 0x26, 0x1d, 0x66, 0x86, 0x8c, - 0x89, 0xfc, 0xba, 0x2d, 0x80, 0x0e, 0x56, 0xc7, 0x6f, 0x2e, 0x2f, 0x87, 0x93, 0x03, 0x7a, 0xb0, - 0x23, 0x93, 0x04, 0xff, 0x03, 0x5a, 0xf0, 0x9a, 0xb5, 0xf3, 0x54, 0xa2, 0x1a, 0xa7, 0x48, 0x6d, - 0xb1, 0xbe, 0x7a, 0xc9, 0xb5, 0x4d, 0xc1, 0xf1, 0x05, 0x61, 0x6d, 0x09, 0x94, 0xb8, 0x8a, 0xaf, - 0xac, 0x57, 0x6f, 0x3b, 0x4f, 0x79, 0xb9, 0xb9, 0x05, 0xa8, 0xb5, 0xec, 0x08, 0x10, 0x3e, 0x40, - 0xa7, 0xdc, 0x25, 0x57, 0x64, 0x9f, 0x05, 0xd9, 0x17, 0xbd, 0xec, 0x63, 0xd3, 0xef, 0x1f, 0x2e, - 0x7a, 0x3e, 0x1e, 0xc5, 0xc1, 0xcf, 0xd0, 0x5c, 0xaa, 0xd8, 0x3e, 0x13, 0xa6, 0xcd, 0x0e, 0x58, - 0xb4, 0xcf, 0x1a, 0x0b, 0xa4, 0xb6, 0x38, 0xb5, 0xb6, 0x01, 0xc8, 0x7f, 0x85, 0xdf, 0xdb, 0xea, - 0x3a, 0xaf, 0xe7, 0x36, 0x43, 0x99, 0x6b, 0xc4, 0x53, 0x13, 0xaa, 0x3a, 0xdc, 0x28, 0x9b, 0x48, - 0x6d, 0x7c, 0x13, 0xcb, 0x9c, 0x39, 0xe1, 0x85, 0xa7, 0x06, 0xe1, 0xac, 0xa7, 0xde, 0x04, 0x68, - 0xfc, 0x71, 0xd9, 0xeb, 0x61, 0xb0, 0x6e, 0xce, 0x5b, 0xe7, 0x9b, 0xd1, 0xd1, 0x36, 0x25, 0x6f, - 0xf9, 0xb8, 0xe8, 0x4a, 0x35, 0x70, 0x96, 0x75, 0xa5, 0xaa, 0xb6, 0x2a, 0x95, 0x26, 0x4f, 0xa1, - 0x53, 0x31, 0xeb, 0xd2, 0x2c, 0x31, 0x6d, 0xeb, 0x24, 0x43, 0xca, 0x4d, 0xe3, 0x34, 0x38, 0xc9, - 0x07, 0x00, 0xba, 0x86, 0xef, 0x58, 0x50, 0x4f, 0x63, 0x9d, 0x05, 0xba, 0x1f, 0x9b, 0xf1, 0x2c, - 0x2d, 0xe9, 0xb0, 0xae, 0xb4, 0xde, 0x69, 0x93, 0x82, 0x88, 0xa1, 0x7d, 0xb0, 0x1d, 0xc5, 0x93, - 0x47, 0xdb, 0x44, 0x31, 0x9d, 0x25, 0xd6, 0x9c, 0x39, 0xcf, 0xfd, 0x80, 0x1e, 0x3c, 0xa5, 0xdc, - 0x34, 0x7f, 0x5a, 0x43, 0xd3, 0xad, 0x9d, 0x2d, 0x5f, 0x07, 0xfe, 0xbb, 0x86, 0x66, 0x3a, 0x5c, - 0xc4, 0x6d, 0x1a, 0xc7, 0x8a, 0x69, 0xed, 0x8b, 0xe1, 0x3e, 0x88, 0x4f, 0xb1, 0x68, 0xb9, 0x65, - 0xc8, 0xe6, 0x5c, 0xc4, 0xa4, 0x17, 0xee, 0xac, 0x13, 0x26, 0xe2, 0x54, 0x72, 0x97, 0x8f, 0xec, - 0x11, 0xbb, 0xd2, 0x96, 0xe9, 0x8c, 0x26, 0xc9, 0x21, 0x91, 0x22, 0x81, 0xe2, 0xb6, 0xb2, 0xfa, - 0x56, 0xb0, 0x1c, 0x2c, 0x07, 0x2b, 0xd7, 0x88, 0x34, 0x7d, 0xa6, 0x86, 0x5c, 0x33, 0xbb, 0xae, - 0x33, 0x05, 0x16, 0xa4, 0x4a, 0xa6, 0x4c, 0x25, 0x36, 0x87, 0x46, 0x76, 0x89, 0x9b, 0x20, 0xac, - 0x5b, 0x21, 0x5e, 0x26, 0x7e, 0x13, 0x4d, 0x83, 0x6a, 0xa9, 0x54, 0x06, 0x8a, 0xea, 0xec, 0x5a, - 0x03, 0xf4, 0xc2, 0xf8, 0xd4, 0x8e, 0x54, 0xa6, 0x50, 0xca, 0x66, 0xfd, 0x29, 0xfb, 0x9f, 0x5d, - 0x6d, 0xfe, 0xdf, 0x04, 0x9a, 0xbe, 0xb7, 0x97, 0x1b, 0xf8, 0x5f, 0xc7, 0x1b, 0x98, 0x01, 0x90, - 0xc4, 0x83, 0xa3, 0x06, 0xde, 0xdb, 0xdb, 0xfa, 0xd3, 0xb6, 0x0f, 0xff, 0x67, 0x0d, 0xcd, 0x72, - 0x61, 0x98, 0x12, 0x34, 0x69, 0x47, 0x3c, 0x56, 0x8d, 0x71, 0xa8, 0x9c, 0x0a, 0x78, 0x13, 0xfc, - 0xe9, 0xfa, 0xd6, 0x46, 0x48, 0xbc, 0xb9, 0x0c, 0x6a, 0x72, 0x4e, 0x4e, 0x04, 0x33, 0x43, 0xa9, - 0x9e, 0x69, 0xb2, 0xc8, 0x82, 0x5e, 0x40, 0x56, 0xde, 0x59, 0x0d, 0x56, 0x6e, 0xbe, 0x6d, 0xcd, - 0x58, 0x5a, 0xb9, 0x79, 0x35, 0x20, 0x4f, 0x19, 0x81, 0xd6, 0xd5, 0x9a, 0x6d, 0x9b, 0xd6, 0xbe, - 0x1c, 0x42, 0x54, 0xe6, 0x00, 0x4b, 0xec, 0xc0, 0x23, 0xf1, 0xc8, 0x16, 0x87, 0x99, 0x7c, 0x63, - 0x9d, 0xc7, 0x0a, 0x7f, 0x5e, 0x43, 0x53, 0xfb, 0xa9, 0x70, 0x4a, 0x9d, 0x00, 0xa5, 0x06, 0xa0, - 0x54, 0x0f, 0xb3, 0xe7, 0x95, 0xda, 0x4f, 0xc5, 0xf7, 0xae, 0xcf, 0xe4, 0x7e, 0x2a, 0x40, 0x15, - 0x86, 0xce, 0xf5, 0xa4, 0xec, 0x25, 0xac, 0x2d, 0x69, 0x66, 0xfa, 0x6d, 0x17, 0x7a, 0x6d, 0x1e, - 0xfb, 0x49, 0xa8, 0x08, 0xda, 0x2d, 0x9b, 0x71, 0x8d, 0x0d, 0x21, 0x2b, 0x08, 0x88, 0x89, 0xfd, - 0x60, 0x76, 0x42, 0xf3, 0xf1, 0x9b, 0xc8, 0x61, 0x10, 0x9e, 0x76, 0x78, 0x1f, 0xd9, 0x4d, 0xd7, - 0x4a, 0x6d, 0xc5, 0x78, 0x80, 0x2e, 0x1c, 0x27, 0x46, 0xb3, 0x48, 0x31, 0xd3, 0x98, 0xf8, 0x23, - 0x45, 0x9d, 0x7f, 0x4e, 0xd4, 0x63, 0x00, 0xc4, 0x9b, 0x08, 0xa5, 0x59, 0x27, 0xe1, 0x91, 0xed, - 0x98, 0xfc, 0x04, 0xf6, 0x3a, 0xc0, 0x13, 0xfc, 0x92, 0xcd, 0x14, 0x6e, 0xd7, 0xb6, 0x4a, 0x2e, - 0x9f, 0x42, 0x02, 0x84, 0xe9, 0x24, 0x9c, 0x76, 0x7b, 0x7b, 0x2a, 0x69, 0xfe, 0x7f, 0x0d, 0x4d, - 0xad, 0xb7, 0x7c, 0x80, 0xfc, 0x47, 0x6d, 0x74, 0xae, 0x3b, 0x12, 0x1f, 0x80, 0x5a, 0x19, 0xe7, - 0x7c, 0x9a, 0x5e, 0x6f, 0x1d, 0xd3, 0x24, 0x71, 0xed, 0xba, 0x8b, 0x48, 0x2a, 0xc5, 0x74, 0x2a, - 0x45, 0xd1, 0x11, 0xb1, 0x91, 0xf6, 0x8a, 0x0b, 0x3f, 0x2b, 0x05, 0xa3, 0xbd, 0xd9, 0xc8, 0x6c, - 0xd8, 0xfc, 0xd5, 0x09, 0x34, 0x77, 0x57, 0x49, 0x61, 0x98, 0x88, 0xbd, 0xae, 0xff, 0x74, 0x7c, - 0x30, 0xff, 0x2d, 0x28, 0xfb, 0x14, 0xef, 0x1d, 0x0d, 0xe6, 0xae, 0x67, 0xaf, 0x44, 0x74, 0x3e, - 0xa4, 0x55, 0x46, 0x33, 0x38, 0xa6, 0x9c, 0x02, 0x22, 0x57, 0x26, 0x09, 0x64, 0xed, 0x4f, 0x65, - 0x47, 0x7f, 0x3f, 0x41, 0xfb, 0x10, 0xd5, 0xab, 0x4d, 0xe8, 0xf8, 0xe8, 0x0b, 0xc4, 0x5f, 0xbf, - 0xb9, 0xfc, 0x0e, 0xa9, 0xf4, 0x8a, 0xf6, 0x94, 0x0b, 0xdd, 0xf3, 0x0b, 0xac, 0x02, 0xe0, 0xee, - 0xe8, 0xa5, 0xb9, 0x37, 0x82, 0x4d, 0xc0, 0xbb, 0x8d, 0xdf, 0xff, 0x1d, 0x97, 0x76, 0x04, 0xf2, - 0xc8, 0x0d, 0x12, 0x57, 0xb1, 0x46, 0x07, 0xf4, 0x27, 0x68, 0xc1, 0xfb, 0x74, 0xc2, 0xa8, 0x66, - 0xe5, 0x63, 0xc2, 0x6c, 0x39, 0x30, 0x7d, 0x20, 0x87, 0xee, 0xd9, 0xc4, 0x48, 0x02, 0x54, 0x79, - 0xef, 0x3a, 0x60, 0x5a, 0xd3, 0x1e, 0xd3, 0x41, 0x38, 0xef, 0x56, 0xb6, 0xed, 0xae, 0x9d, 0xcd, - 0xf1, 0x1d, 0x34, 0x15, 0x0b, 0xed, 0xe6, 0x2f, 0x17, 0x26, 0xaf, 0x01, 0xdc, 0x65, 0x7c, 0xc9, - 0x2a, 0xbf, 0xf1, 0xf0, 0xf1, 0xc8, 0x0c, 0x96, 0x6b, 0x1e, 0x84, 0x93, 0xb1, 0xd0, 0x30, 0x76, - 0x3d, 0x46, 0x73, 0xb6, 0xdc, 0x75, 0x69, 0x64, 0xb4, 0x9b, 0xbb, 0x26, 0x47, 0x0f, 0xd5, 0x0e, - 0x3e, 0x56, 0x25, 0x1a, 0xc7, 0xdc, 0x06, 0x17, 0x4d, 0x48, 0xc1, 0x00, 0xaa, 0x4a, 0x1a, 0x87, - 0xb3, 0xc5, 0x12, 0xcc, 0x49, 0xdf, 0x8c, 0xa1, 0xf9, 0x0d, 0x6a, 0xa8, 0x36, 0x52, 0x31, 0xef, - 0x74, 0x1a, 0xcd, 0xf1, 0x41, 0x9a, 0xb0, 0x01, 0x13, 0x6e, 0x14, 0xf7, 0x5e, 0x77, 0x1f, 0x04, - 0x6d, 0xe2, 0xe5, 0xa3, 0x03, 0x63, 0x9c, 0x03, 0x90, 0x51, 0x3e, 0x2b, 0x34, 0xd3, 0x2c, 0x58, - 0x5d, 0xb8, 0xcb, 0x13, 0xb6, 0x46, 0x35, 0xb3, 0xa2, 0x1e, 0x5b, 0xca, 0xf0, 0x88, 0x08, 0xbc, - 0x8d, 0xa6, 0xf2, 0x19, 0xcf, 0xcf, 0x93, 0xa3, 0xaf, 0x21, 0xf9, 0xfc, 0xb7, 0x28, 0x15, 0xf4, - 0xa9, 0x57, 0x9d, 0x23, 0x57, 0x84, 0x07, 0x61, 0x81, 0x80, 0x3f, 0x46, 0xa7, 0xbb, 0x3c, 0x61, - 0xb0, 0xde, 0x8e, 0xb9, 0x62, 0x91, 0x91, 0xea, 0xd0, 0x7b, 0xe1, 0x55, 0x00, 0x7e, 0x05, 0xbf, - 0x0c, 0x5e, 0xe3, 0x0f, 0xcd, 0xe9, 0x9f, 0xa5, 0xf6, 0x90, 0x58, 0x4c, 0x80, 0x3b, 0x08, 0x71, - 0x81, 0xb2, 0x91, 0x83, 0x34, 0xbf, 0xaa, 0xa1, 0xfa, 0x5d, 0x3b, 0x0c, 0xfa, 0xe3, 0xfa, 0xf7, - 0x1a, 0x7a, 0x09, 0xd2, 0xb3, 0x92, 0x3d, 0xeb, 0x9e, 0xe5, 0xf1, 0xb7, 0x3f, 0xcb, 0x98, 0xe2, - 0xcc, 0x46, 0xed, 0xf8, 0x62, 0x7d, 0x75, 0x21, 0xef, 0xa3, 0x1e, 0x6d, 0x87, 0xec, 0xb3, 0x8c, - 0x69, 0xb3, 0xf6, 0x0e, 0xa8, 0x72, 0x1d, 0xaf, 0xb4, 0xca, 0x3b, 0xf3, 0x4c, 0x56, 0x29, 0xae, - 0x75, 0x06, 0xa5, 0x75, 0xab, 0xc4, 0x87, 0x94, 0xa9, 0x83, 0xf0, 0x62, 0x45, 0x66, 0xc9, 0xfd, - 0xc8, 0x31, 0x37, 0x7f, 0x52, 0xcb, 0xe7, 0xdf, 0x4d, 0xdb, 0xda, 0x69, 0xcc, 0xd0, 0x74, 0x71, - 0xf3, 0xa0, 0x4f, 0xe5, 0x0d, 0xcf, 0x91, 0xb8, 0x1e, 0xbf, 0xc3, 0x48, 0x24, 0x13, 0x3f, 0xe4, - 0x16, 0x2f, 0x3e, 0xde, 0xbf, 0xdd, 0x83, 0x9e, 0xe9, 0x33, 0xcd, 0x4a, 0xd7, 0x0a, 0xc2, 0x12, - 0x19, 0x3f, 0x2a, 0x9b, 0xc7, 0x31, 0xe8, 0xeb, 0xde, 0x02, 0x21, 0x2b, 0x78, 0xa9, 0x65, 0x7b, - 0xc4, 0x48, 0xc1, 0x95, 0x5b, 0x94, 0xbc, 0x71, 0xb4, 0x13, 0xb4, 0x13, 0x68, 0xbf, 0x29, 0x77, - 0x30, 0xba, 0xec, 0x19, 0x9b, 0x5f, 0x8c, 0x23, 0xf4, 0x80, 0xf2, 0xc4, 0x1f, 0x37, 0x43, 0x27, - 0xac, 0x5a, 0xde, 0x27, 0x1f, 0x01, 0xfc, 0x7d, 0xbc, 0xe5, 0x1e, 0x1d, 0xac, 0xae, 0x6c, 0x40, - 0x79, 0x92, 0xf7, 0x30, 0x1d, 0xe8, 0x14, 0x0d, 0x58, 0x12, 0x90, 0xad, 0x2e, 0x0c, 0x8a, 0x95, - 0xa2, 0x64, 0x19, 0xa0, 0x90, 0x65, 0xda, 0x96, 0x55, 0x78, 0x41, 0xb5, 0xb4, 0xf8, 0x5d, 0x34, - 0xe1, 0x92, 0x86, 0xf7, 0xc6, 0x57, 0x40, 0xd0, 0x25, 0xfc, 0x62, 0x9e, 0x72, 0xbd, 0xef, 0x3f, - 0x7e, 0xb0, 0xbb, 0x53, 0x64, 0x2c, 0xcf, 0x82, 0xef, 0x14, 0x83, 0x3e, 0x64, 0xcd, 0x71, 0x38, - 0x89, 0xcb, 0x80, 0xf0, 0x02, 0x3e, 0x0f, 0x59, 0xf3, 0x79, 0xf6, 0x7c, 0x8e, 0x87, 0xf4, 0xf9, - 0x01, 0x9a, 0x1d, 0x51, 0xcb, 0x27, 0xbc, 0x42, 0x0b, 0x9b, 0x11, 0x20, 0xd6, 0xcb, 0x72, 0xca, - 0x48, 0x26, 0x62, 0xab, 0xc5, 0x8c, 0x5d, 0xdc, 0xf3, 0x8c, 0xf8, 0xbe, 0x47, 0x4a, 0xa9, 0xd6, - 0x43, 0xa9, 0xf2, 0x7e, 0xa0, 0xa8, 0xa2, 0xf9, 0xfa, 0x73, 0x68, 0xb6, 0x92, 0x79, 0xb0, 0x1d, - 0x4f, 0xd3, 0xfc, 0x97, 0x31, 0x34, 0xbb, 0x2d, 0x7b, 0x3d, 0x2e, 0x7a, 0xfe, 0x3a, 0x32, 0x74, - 0x4a, 0x66, 0x26, 0xcd, 0x4c, 0x25, 0xcc, 0xdc, 0xd5, 0x7c, 0x08, 0x12, 0x36, 0xf0, 0xda, 0x48, - 0xfc, 0xda, 0x4e, 0xde, 0x8f, 0x91, 0x3d, 0x1f, 0x65, 0x47, 0xae, 0xc5, 0x6d, 0x0b, 0x59, 0xa1, - 0x08, 0xe7, 0x9d, 0x8c, 0x22, 0x08, 0xf1, 0xdf, 0xa3, 0x17, 0x35, 0x4b, 0xa9, 0xb2, 0x01, 0x97, - 0xc8, 0x9e, 0x6e, 0xa7, 0x4c, 0xb5, 0x23, 0x39, 0x48, 0xa5, 0x60, 0xc2, 0xd5, 0xa9, 0xa9, 0x72, - 0x50, 0x77, 0x8d, 0xc8, 0x35, 0xc2, 0x68, 0xd4, 0x27, 0x05, 0x95, 0x73, 0x78, 0x2b, 0xc5, 0x9a, - 0x4e, 0x72, 0x3c, 0x90, 0x19, 0x84, 0x8d, 0xfc, 0xfb, 0xb6, 0xec, 0xe9, 0x1d, 0x3b, 0xcc, 0x79, - 0xb6, 0xe6, 0x37, 0xd3, 0x68, 0xc2, 0x5b, 0x7f, 0xb7, 0x74, 0xf7, 0xa9, 0x63, 0x67, 0xa5, 0x8b, - 0xa0, 0xc2, 0x39, 0x7c, 0xe6, 0xc9, 0xf3, 0x73, 0x52, 0x65, 0x2e, 0xfa, 0x10, 0x4d, 0xb8, 0x68, - 0x85, 0xb3, 0xab, 0xaf, 0x9e, 0xf6, 0x30, 0xd5, 0x27, 0xac, 0xb5, 0x4b, 0x80, 0x75, 0x1e, 0x9f, - 0x75, 0xab, 0x47, 0xdf, 0x2d, 0x3c, 0x02, 0xde, 0x45, 0x13, 0x2e, 0xa0, 0x61, 0xc0, 0x3f, 0x8a, - 0xe5, 0xb6, 0xca, 0xd7, 0x75, 0x1f, 0xfb, 0xf0, 0xa4, 0x04, 0x51, 0xe8, 0x82, 0xbe, 0x18, 0x0e, - 0x3d, 0x16, 0xde, 0x41, 0xe3, 0xad, 0x9d, 0x2d, 0x38, 0xd8, 0xfa, 0xea, 0x29, 0x0f, 0x59, 0x8c, - 0x55, 0x65, 0x11, 0x1a, 0x9d, 0x71, 0x6d, 0x4f, 0x01, 0x13, 0x54, 0x6b, 0xa7, 0x32, 0x65, 0x84, - 0x16, 0x0a, 0x37, 0xd1, 0xf8, 0xbd, 0xbd, 0x2d, 0x08, 0x8e, 0x12, 0xb1, 0x98, 0x63, 0x42, 0xbb, - 0x89, 0x2f, 0xa3, 0xb1, 0xf5, 0x16, 0xf8, 0x7e, 0x7d, 0x75, 0x3e, 0xb7, 0xc3, 0x37, 0x72, 0xe1, - 0xd8, 0x7a, 0x0b, 0xaf, 0xa0, 0xa9, 0xbc, 0x65, 0x02, 0xc7, 0xae, 0xaf, 0x9e, 0xf5, 0x64, 0xa3, - 0x9d, 0x54, 0x58, 0x90, 0xe1, 0x1b, 0x68, 0xba, 0xa8, 0x78, 0x50, 0x8a, 0xeb, 0xab, 0xe7, 0x8a, - 0xf9, 0x7d, 0xa4, 0x12, 0x86, 0x25, 0x21, 0x5e, 0x44, 0x27, 0x21, 0xe9, 0x43, 0xd1, 0xad, 0xaf, - 0xe2, 0x5c, 0x4a, 0x59, 0x08, 0x42, 0x47, 0x80, 0x87, 0x95, 0xdf, 0x10, 0xe0, 0x29, 0xa7, 0xb4, - 0xae, 0x58, 0x2f, 0x73, 0xef, 0x3a, 0x68, 0x65, 0x8a, 0x7c, 0x52, 0xbc, 0x4a, 0xc1, 0x03, 0x0b, - 0xa1, 0xda, 0x55, 0xa6, 0xe2, 0xd5, 0xaa, 0x78, 0x6f, 0xf1, 0x6e, 0x5a, 0xf9, 0xbd, 0xe2, 0x35, - 0x74, 0xc2, 0xe6, 0x49, 0x78, 0xf0, 0x2b, 0xab, 0x4d, 0x99, 0x3a, 0x43, 0xd8, 0xc6, 0x01, 0x9a, - 0xf4, 0x21, 0xdc, 0x38, 0x0f, 0x94, 0x67, 0x3c, 0xe5, 0x48, 0x60, 0x87, 0x39, 0x11, 0xbe, 0x03, - 0x3e, 0xde, 0x91, 0x9a, 0xc1, 0xfb, 0xd7, 0x54, 0x99, 0x3a, 0x36, 0x05, 0xed, 0x24, 0xf0, 0x04, - 0x60, 0x77, 0x6d, 0x24, 0x59, 0x06, 0xe2, 0x62, 0xd5, 0x79, 0xb7, 0xdd, 0xc0, 0x5f, 0x8e, 0xa1, - 0x79, 0x9a, 0x19, 0x69, 0xfb, 0xb9, 0x76, 0x2c, 0x07, 0x94, 0x0b, 0x78, 0x38, 0x99, 0x5e, 0xfb, - 0xb5, 0x7b, 0x12, 0xfc, 0xb6, 0x86, 0x7f, 0x59, 0xdb, 0x80, 0x0d, 0xdf, 0x33, 0x80, 0xe7, 0xe4, - 0x3c, 0x9a, 0x2c, 0x26, 0xcc, 0x68, 0x26, 0x22, 0x75, 0x98, 0x9a, 0xab, 0xd5, 0xce, 0xbb, 0xc3, - 0xec, 0xe0, 0x2f, 0x93, 0x7d, 0xd0, 0xc4, 0xb7, 0x04, 0x45, 0xdb, 0xb7, 0xcf, 0xa9, 0xed, 0xac, - 0x82, 0x87, 0x1f, 0xed, 0x6e, 0xde, 0x22, 0xfe, 0x37, 0xa0, 0xca, 0x33, 0x49, 0x47, 0xfa, 0x66, - 0xdd, 0x0e, 0xc1, 0xb4, 0xda, 0x3f, 0x43, 0x6a, 0xb0, 0x7a, 0xd8, 0x04, 0xae, 0xc9, 0xdb, 0xcb, - 0xb0, 0x7d, 0xe3, 0xc6, 0x75, 0xf2, 0x97, 0x95, 0x6b, 0x0a, 0x2a, 0xcf, 0xb9, 0x85, 0x3e, 0x79, - 0x07, 0x27, 0xd5, 0x80, 0x90, 0xbe, 0x31, 0xa9, 0xbe, 0xb5, 0xb4, 0x74, 0xc4, 0xfc, 0xa5, 0x70, - 0x2e, 0x5f, 0x71, 0x66, 0xe3, 0x4f, 0xd0, 0xe9, 0x82, 0xc6, 0x7d, 0xd0, 0xa8, 0xcf, 0x1a, 0xe7, - 0x8e, 0x6f, 0xf1, 0x5c, 0xb7, 0x92, 0x33, 0x54, 0x67, 0x0d, 0x1d, 0x84, 0x0b, 0xf9, 0xba, 0x6d, - 0xb0, 0xd7, 0x2d, 0x4c, 0x67, 0x02, 0x6e, 0xf8, 0xfa, 0x6f, 0x03, 0x00, 0x00, 0xff, 0xff, 0xad, - 0x94, 0xcb, 0xc6, 0xe4, 0x1c, 0x00, 0x00, + 0x1f, 0xb0, 0xe6, 0x37, 0xe3, 0x68, 0xfa, 0xa9, 0xe2, 0x86, 0x75, 0x68, 0xf4, 0x0c, 0x87, 0xa8, + 0x9e, 0x2a, 0xbe, 0x4f, 0x0d, 0x6b, 0x3f, 0x63, 0x87, 0x8d, 0x49, 0x40, 0x5c, 0x01, 0xc4, 0x3f, + 0xc3, 0x57, 0x47, 0xd4, 0xf2, 0x74, 0xe4, 0x19, 0x3b, 0x24, 0x5c, 0x90, 0x9d, 0xcd, 0x07, 0x84, + 0x89, 0x48, 0xc6, 0xa0, 0x20, 0xf2, 0x5f, 0xef, 0xb3, 0x43, 0xfc, 0xd7, 0xe8, 0x74, 0x3f, 0x13, + 0xa6, 0x9d, 0x50, 0x6d, 0x40, 0x51, 0x6d, 0xe8, 0x20, 0x6d, 0xcc, 0x92, 0xda, 0xe2, 0x89, 0xb5, + 0x65, 0xc0, 0x7e, 0x03, 0x2f, 0x5a, 0x6c, 0x4b, 0x41, 0x2c, 0x2d, 0x29, 0xc8, 0x88, 0xe9, 0x73, + 0x9d, 0x5b, 0xa0, 0xa8, 0x08, 0xc2, 0x05, 0x4b, 0xb0, 0x4d, 0xb5, 0xd9, 0xcd, 0x69, 0xf0, 0x2f, + 0x6a, 0xe8, 0x05, 0x40, 0xd7, 0x4c, 0xed, 0x33, 0x65, 0xff, 0xe1, 0x34, 0x69, 0x8b, 0x6c, 0xd0, + 0x61, 0xaa, 0x31, 0x07, 0x82, 0xbe, 0xa9, 0x81, 0xa4, 0xff, 0xab, 0xe1, 0xaf, 0x6b, 0x85, 0xac, + 0x88, 0x29, 0xc3, 0xbb, 0x3c, 0xb2, 0x76, 0x38, 0x26, 0xe2, 0x98, 0xc8, 0x90, 0x11, 0x4d, 0x87, + 0xa4, 0xab, 0xe4, 0x00, 0xee, 0xd0, 0x21, 0x07, 0x64, 0x1d, 0x34, 0xd1, 0x44, 0xb1, 0x6e, 0xa6, + 0x19, 0x31, 0x92, 0x44, 0x52, 0x08, 0x16, 0x19, 0xfb, 0x5f, 0x47, 0xa4, 0xc9, 0x90, 0x9b, 0x3e, + 0x91, 0x49, 0xcc, 0xd4, 0x28, 0xaa, 0x26, 0x54, 0x93, 0x94, 0x2a, 0x43, 0x64, 0xd7, 0x13, 0xc3, + 0xf5, 0x29, 0x69, 0x28, 0xf8, 0x21, 0x44, 0x41, 0x24, 0x93, 0x20, 0x3c, 0x67, 0xf5, 0x7b, 0x0c, + 0x24, 0x8f, 0x01, 0xe2, 0x21, 0x20, 0x34, 0xff, 0x79, 0x0c, 0x9d, 0x7b, 0xca, 0x45, 0x2c, 0x87, + 0x7a, 0x4b, 0x68, 0x43, 0x93, 0x84, 0xa9, 0x75, 0x08, 0x62, 0xfc, 0x00, 0xcd, 0x58, 0x4c, 0x1e, + 0xb1, 0x76, 0x25, 0x70, 0xde, 0x00, 0xb3, 0x5f, 0xc5, 0x4d, 0x6b, 0xb4, 0x3d, 0xb7, 0xb2, 0x73, + 0x8b, 0x78, 0xe4, 0x4c, 0x50, 0x8c, 0x1a, 0x16, 0x84, 0x75, 0x7f, 0xf6, 0xd0, 0xc6, 0xd3, 0x57, + 0x35, 0x34, 0xc3, 0x9d, 0x88, 0x76, 0x4a, 0x4d, 0xdf, 0x47, 0xd4, 0xdf, 0x01, 0xde, 0x01, 0xde, + 0x7f, 0xda, 0x67, 0x8a, 0x11, 0xdd, 0x97, 0x59, 0x12, 0x03, 0x60, 0x87, 0x0b, 0xaa, 0x0e, 0x49, + 0x87, 0x11, 0xcf, 0xc6, 0xe2, 0xdb, 0xc4, 0x4a, 0xf5, 0xbf, 0x82, 0x13, 0x53, 0x11, 0x93, 0x48, + 0xa6, 0x9c, 0xe9, 0x2a, 0x8f, 0x91, 0xee, 0x9d, 0x13, 0x19, 0xb9, 0x8b, 0xb0, 0x64, 0x9e, 0x4d, + 0x57, 0xb5, 0x0d, 0xc2, 0xba, 0x3f, 0xde, 0xa1, 0xa6, 0xdf, 0xfc, 0xa7, 0x31, 0x74, 0x76, 0x83, + 0xaa, 0x21, 0x17, 0x7f, 0xba, 0x8c, 0xe6, 0x17, 0x33, 0x68, 0xc6, 0xb9, 0xa7, 0xbf, 0x83, 0x7f, + 0xa8, 0xa1, 0x89, 0x84, 0x76, 0x58, 0xa2, 0x1b, 0x13, 0x64, 0x7c, 0x71, 0x7a, 0x8d, 0x83, 0xba, + 0x11, 0xa6, 0x2d, 0x92, 0x70, 0x0d, 0x5e, 0xe8, 0xbe, 0x57, 0xd3, 0x44, 0x9f, 0xea, 0x80, 0xec, + 0x5a, 0x05, 0x68, 0x92, 0xc8, 0xa1, 0x26, 0x9a, 0x25, 0x2c, 0x32, 0x2c, 0x26, 0x3d, 0x25, 0xb3, + 0x54, 0x5b, 0xae, 0xc8, 0x47, 0x81, 0x91, 0xd6, 0x42, 0x43, 0x55, 0x8f, 0x19, 0x4b, 0xc1, 0x05, + 0x84, 0xaf, 0x0e, 0x42, 0x2f, 0x18, 0x53, 0x54, 0xf7, 0x41, 0x99, 0xa9, 0x44, 0x37, 0xa6, 0x40, + 0x8f, 0x3b, 0xa0, 0xc7, 0x2d, 0xfc, 0x76, 0xa9, 0x87, 0x8f, 0x86, 0xbd, 0x70, 0x7b, 0x44, 0x99, + 0x21, 0x4f, 0x12, 0x62, 0xdc, 0xa5, 0x94, 0x81, 0x16, 0x84, 0xc8, 0xd1, 0xef, 0xa9, 0x44, 0xe3, + 0x2f, 0x6b, 0x68, 0x2e, 0xa2, 0xed, 0x4a, 0x2c, 0x37, 0xea, 0xf0, 0x3a, 0x1d, 0x10, 0xf3, 0x29, + 0xfe, 0xc4, 0xde, 0xfb, 0x7a, 0xeb, 0x8a, 0x1e, 0x89, 0x77, 0x48, 0x56, 0x4e, 0xe7, 0x9d, 0xcd, + 0x07, 0x01, 0xd9, 0x7d, 0x4e, 0x6a, 0xa6, 0x0d, 0xa1, 0xe2, 0x30, 0xd7, 0x4d, 0xf3, 0x9e, 0x60, + 0xb1, 0x0b, 0x6e, 0x78, 0xa0, 0xf5, 0x56, 0x10, 0xce, 0x46, 0x74, 0xbd, 0x04, 0xc5, 0xff, 0x5f, + 0x43, 0x27, 0x85, 0x14, 0x11, 0x6b, 0xcc, 0x80, 0x0a, 0xff, 0xeb, 0xb2, 0xce, 0x7f, 0xd5, 0xf0, + 0x7f, 0xd6, 0x5a, 0x44, 0xf7, 0xa9, 0x62, 0x31, 0x01, 0x82, 0xe7, 0xac, 0x4c, 0x15, 0xd3, 0x4c, + 0x18, 0xa7, 0x88, 0x17, 0x09, 0x1f, 0x14, 0xfb, 0xcc, 0x9a, 0x9d, 0xdf, 0xf9, 0xb0, 0xcf, 0xa3, + 0x3e, 0x89, 0x25, 0x11, 0xd2, 0xe4, 0x4c, 0x4e, 0x1f, 0x9b, 0x4a, 0xb4, 0x24, 0xdc, 0x90, 0x81, + 0x55, 0xbd, 0xc3, 0x08, 0x1b, 0x74, 0x58, 0xec, 0x8d, 0x34, 0xd5, 0xe4, 0xed, 0xea, 0x7e, 0xa6, + 0xc0, 0xc1, 0x82, 0xd0, 0xe9, 0x8c, 0xbb, 0xe8, 0xd4, 0x30, 0x2f, 0x05, 0xed, 0x18, 0xe2, 0xaa, + 0x71, 0x06, 0xec, 0x78, 0x17, 0xcc, 0x78, 0x13, 0x5f, 0x6f, 0x11, 0xeb, 0xfe, 0x64, 0x08, 0xfe, + 0xee, 0x48, 0x4a, 0xcd, 0xac, 0xb6, 0x00, 0x00, 0xbe, 0x9b, 0x10, 0x6d, 0x20, 0x92, 0xe6, 0x0b, + 0x50, 0x17, 0xab, 0x38, 0x42, 0xe5, 0x51, 0x3b, 0xe1, 0x22, 0x3b, 0x68, 0x4c, 0x83, 0x98, 0x5b, + 0x20, 0xe6, 0x06, 0x5e, 0x1d, 0x11, 0x03, 0x14, 0xdf, 0x2b, 0x65, 0xae, 0x80, 0xdc, 0xb6, 0xf4, + 0x98, 0xa3, 0x85, 0x52, 0xc8, 0xd0, 0xa5, 0xcc, 0x06, 0x02, 0x31, 0xef, 0x81, 0x98, 0x9b, 0xf8, + 0xc6, 0x88, 0x18, 0x4f, 0xf3, 0xbd, 0x82, 0xca, 0x3b, 0xf2, 0x89, 0x18, 0xff, 0x25, 0x9a, 0x1a, + 0xd0, 0x83, 0x76, 0x2a, 0x93, 0xa4, 0x31, 0x0f, 0xd5, 0x26, 0xf7, 0xf0, 0xeb, 0xf6, 0x31, 0x07, + 0xf4, 0x80, 0x0f, 0xb2, 0x41, 0x5e, 0x5a, 0xc0, 0xdb, 0x23, 0x29, 0x62, 0x4d, 0x3a, 0xcc, 0x0c, + 0x19, 0x13, 0xf9, 0x73, 0x5b, 0x00, 0x1d, 0xac, 0x8e, 0xdf, 0x5c, 0x5e, 0x0e, 0x27, 0x07, 0xf4, + 0x60, 0x47, 0x26, 0x09, 0xfe, 0x5b, 0xb4, 0xe0, 0x35, 0x6b, 0xe7, 0xa9, 0x44, 0x35, 0x4e, 0x91, + 0xda, 0x62, 0x7d, 0xf5, 0x92, 0x6b, 0x9b, 0x82, 0xe3, 0x0b, 0xc2, 0xda, 0x12, 0x28, 0x71, 0x15, + 0x5f, 0x59, 0xaf, 0xbe, 0x76, 0x9e, 0xf2, 0x72, 0x73, 0x0b, 0x50, 0x6b, 0xd9, 0x11, 0x20, 0x7c, + 0x80, 0x4e, 0xb9, 0x47, 0xae, 0xc8, 0x3e, 0x0b, 0xb2, 0x2f, 0x7a, 0xd9, 0xc7, 0xa6, 0xdf, 0xdf, + 0x5f, 0xf4, 0x7c, 0x3c, 0x8a, 0x83, 0x9f, 0xa1, 0xb9, 0x54, 0xb1, 0x7d, 0x26, 0x4c, 0x9b, 0x1d, + 0xb0, 0x68, 0x9f, 0x35, 0x16, 0x48, 0x6d, 0x71, 0x6a, 0x6d, 0x03, 0x90, 0x3f, 0xc0, 0xef, 0x6d, + 0x75, 0x9d, 0xd7, 0x73, 0x9b, 0xa1, 0xcc, 0x35, 0xe2, 0xa9, 0x09, 0x55, 0x1d, 0x6e, 0x94, 0x4d, + 0xa4, 0x36, 0xbe, 0x89, 0x65, 0xce, 0x9c, 0xf0, 0xc2, 0x53, 0x83, 0x70, 0xd6, 0x53, 0x6f, 0x02, + 0x34, 0xfe, 0xa4, 0xec, 0xf5, 0x30, 0x58, 0x37, 0xe7, 0xad, 0xf3, 0xcd, 0xe8, 0x68, 0x9b, 0x92, + 0xb7, 0x7c, 0x5c, 0x74, 0xa5, 0x1a, 0x38, 0xcb, 0xba, 0x52, 0x55, 0x5b, 0x95, 0x4a, 0x93, 0xa7, + 0xd0, 0xa9, 0x98, 0x75, 0x69, 0x96, 0x98, 0xb6, 0x75, 0x92, 0x21, 0xe5, 0xa6, 0x71, 0x1a, 0x9c, + 0xe4, 0x43, 0x00, 0x5d, 0xc3, 0x77, 0x2c, 0xa8, 0xa7, 0xb1, 0xce, 0x02, 0xdd, 0x8f, 0xcd, 0x78, + 0x96, 0x96, 0x74, 0x58, 0x57, 0x5a, 0xef, 0xb4, 0x49, 0x41, 0xc4, 0xd0, 0x3e, 0xd8, 0x8e, 0xe2, + 0xc9, 0xa3, 0x6d, 0xa2, 0x98, 0xce, 0x12, 0x6b, 0xce, 0x9c, 0xe7, 0x7e, 0x40, 0x0f, 0x9e, 0x52, + 0x6e, 0x9a, 0x3f, 0xad, 0xa1, 0xe9, 0xd6, 0xce, 0x96, 0xaf, 0x03, 0xff, 0x51, 0x43, 0x33, 0x1d, + 0x2e, 0xe2, 0x36, 0x8d, 0x63, 0xc5, 0xb4, 0xf6, 0xc5, 0x70, 0x1f, 0xc4, 0xa7, 0x58, 0xb4, 0xdc, + 0x31, 0x64, 0x73, 0x2e, 0x62, 0xd2, 0x0b, 0x77, 0xd6, 0x09, 0x13, 0x71, 0x2a, 0xb9, 0xcb, 0x47, + 0xf6, 0x8a, 0x5d, 0x69, 0xcb, 0x74, 0x46, 0x93, 0xe4, 0x90, 0x48, 0x91, 0x40, 0x71, 0x5b, 0x59, + 0x7d, 0x2b, 0x58, 0x0e, 0x96, 0x83, 0x95, 0x6b, 0x44, 0x9a, 0x3e, 0x53, 0x43, 0xae, 0x99, 0x3d, + 0xd7, 0x99, 0x02, 0x0b, 0x52, 0x25, 0x53, 0xa6, 0x12, 0x9b, 0x43, 0x23, 0x7b, 0xc4, 0x4d, 0x10, + 0xd6, 0xad, 0x10, 0x2f, 0x13, 0xbf, 0x89, 0xa6, 0x41, 0xb5, 0x54, 0x2a, 0x03, 0x45, 0x75, 0x76, + 0xad, 0x01, 0x7a, 0x61, 0x7c, 0x6a, 0x47, 0x2a, 0x53, 0x28, 0x65, 0xb3, 0xfe, 0x94, 0xfd, 0x9f, + 0x3d, 0x6d, 0xfe, 0xf7, 0x04, 0x9a, 0xbe, 0xb7, 0x97, 0x1b, 0xf8, 0xef, 0xc7, 0x1b, 0x98, 0x01, + 0x90, 0xc4, 0x83, 0xa3, 0x06, 0xde, 0xdb, 0xdb, 0xfa, 0xe3, 0xb6, 0x0f, 0xff, 0x5b, 0x0d, 0xcd, + 0x72, 0x61, 0x98, 0x12, 0x34, 0x69, 0x47, 0x3c, 0x56, 0x8d, 0x71, 0xa8, 0x9c, 0x0a, 0x78, 0x13, + 0xfc, 0xd9, 0xfa, 0xd6, 0x46, 0x48, 0xbc, 0xb9, 0x0c, 0x6a, 0x72, 0x4e, 0x4e, 0x04, 0x33, 0x43, + 0xa9, 0x9e, 0x69, 0xb2, 0xc8, 0x82, 0x5e, 0x40, 0x56, 0xde, 0x59, 0x0d, 0x56, 0x6e, 0xbe, 0x6d, + 0xcd, 0x58, 0x5a, 0xb9, 0x79, 0x35, 0x20, 0x4f, 0x19, 0x81, 0xd6, 0xd5, 0x9a, 0x6d, 0x9b, 0xd6, + 0xbe, 0x1c, 0x42, 0x54, 0xe6, 0x00, 0x4b, 0xec, 0xc0, 0x23, 0xf1, 0xc8, 0x16, 0x87, 0x99, 0xfc, + 0xc3, 0x3a, 0x8f, 0x15, 0xfe, 0xa2, 0x86, 0xa6, 0xf6, 0x53, 0xe1, 0x94, 0x3a, 0x01, 0x4a, 0x0d, + 0x40, 0xa9, 0x1e, 0x66, 0xcf, 0x2b, 0xb5, 0x9f, 0x8a, 0x1f, 0x5c, 0x9f, 0xc9, 0xfd, 0x54, 0x80, + 0x2a, 0x0c, 0x9d, 0xeb, 0x49, 0xd9, 0x4b, 0x58, 0x5b, 0xd2, 0xcc, 0xf4, 0xdb, 0x2e, 0xf4, 0xda, + 0x3c, 0xf6, 0x93, 0x50, 0x11, 0xb4, 0x5b, 0x36, 0xe3, 0x1a, 0x1b, 0x42, 0x56, 0x10, 0x10, 0x13, + 0xfb, 0x83, 0xd9, 0x09, 0xcd, 0xc7, 0x6f, 0x22, 0x87, 0x41, 0x78, 0xda, 0xe1, 0x7d, 0x6c, 0x3f, + 0xba, 0x56, 0x6a, 0x2b, 0xc6, 0x03, 0x74, 0xe1, 0x38, 0x31, 0x9a, 0x45, 0x8a, 0x99, 0xc6, 0xc4, + 0x1f, 0x28, 0xea, 0xfc, 0x73, 0xa2, 0x1e, 0x03, 0x20, 0xde, 0x44, 0x28, 0xcd, 0x3a, 0x09, 0x8f, + 0x6c, 0xc7, 0xe4, 0x27, 0xb0, 0xd7, 0x01, 0x9e, 0xe0, 0x97, 0x6c, 0xa6, 0x70, 0x5f, 0x6d, 0xab, + 0xe4, 0xf2, 0x29, 0x24, 0x40, 0x98, 0x4e, 0xc2, 0x69, 0xf7, 0x6d, 0x4f, 0x25, 0xcd, 0xff, 0xa9, + 0xa1, 0xa9, 0xf5, 0x96, 0x0f, 0x90, 0x7f, 0xad, 0x8d, 0xce, 0x75, 0x47, 0xe2, 0x03, 0x50, 0x2b, + 0xe3, 0x9c, 0x4f, 0xd3, 0xeb, 0xad, 0x63, 0x9a, 0x24, 0xae, 0x5d, 0x77, 0x11, 0x49, 0xa5, 0x98, + 0x4e, 0xa5, 0x28, 0x3a, 0x22, 0x36, 0xd2, 0x5e, 0x71, 0xe1, 0x67, 0xa5, 0x60, 0xb4, 0x37, 0x1b, + 0x99, 0x0d, 0x9b, 0x3f, 0x39, 0x89, 0xe6, 0xee, 0x2a, 0x29, 0x0c, 0x13, 0xb1, 0xd7, 0xf5, 0xef, + 0x8f, 0x0f, 0xe6, 0xbf, 0x02, 0x65, 0x9f, 0xe2, 0xbd, 0xa3, 0xc1, 0xdc, 0xf5, 0xec, 0x95, 0x88, + 0xce, 0x87, 0xb4, 0xca, 0x68, 0x06, 0xd7, 0x94, 0x53, 0x40, 0xe4, 0xca, 0x24, 0x81, 0xac, 0xfd, + 0x99, 0xec, 0xe8, 0x1f, 0x26, 0x68, 0x1f, 0xa2, 0x7a, 0xb5, 0x09, 0x1d, 0x1f, 0xdd, 0x40, 0xfc, + 0xc5, 0x9b, 0xcb, 0xef, 0x90, 0x4a, 0xaf, 0x68, 0x6f, 0xb9, 0xd0, 0x3d, 0x7f, 0xc0, 0x2a, 0x00, + 0xee, 0x8e, 0x3e, 0x9a, 0xdb, 0x11, 0x6c, 0x02, 0xde, 0x6d, 0xfc, 0xfe, 0x6f, 0x79, 0xb4, 0x23, + 0x90, 0x47, 0x5e, 0x90, 0xb8, 0x8a, 0x35, 0x3a, 0xa0, 0x3f, 0x41, 0x0b, 0xde, 0xa7, 0x13, 0x46, + 0x35, 0x2b, 0x97, 0x09, 0xb3, 0xe5, 0xc0, 0xf4, 0xa1, 0x1c, 0xba, 0xb5, 0x89, 0x91, 0x04, 0xa8, + 0xf2, 0xde, 0x75, 0xc0, 0xb4, 0xa6, 0x3d, 0xa6, 0x83, 0x70, 0xde, 0x9d, 0x6c, 0xdb, 0xaf, 0x76, + 0x36, 0xc7, 0x77, 0xd0, 0x54, 0x2c, 0xb4, 0x9b, 0xbf, 0x5c, 0x98, 0xbc, 0x06, 0x70, 0x97, 0xf1, + 0x25, 0xab, 0xfc, 0xc6, 0xc3, 0xc7, 0x23, 0x33, 0x58, 0xae, 0x79, 0x10, 0x4e, 0xc6, 0x42, 0xc3, + 0xd8, 0xf5, 0x18, 0xcd, 0xd9, 0x72, 0xd7, 0xa5, 0x91, 0xd1, 0x6e, 0xee, 0x9a, 0x1c, 0xbd, 0x54, + 0x3b, 0xf8, 0x58, 0x95, 0x68, 0x1c, 0x73, 0x1b, 0x5c, 0x34, 0x21, 0x05, 0x03, 0xa8, 0x2a, 0x69, + 0x1c, 0xce, 0x16, 0x47, 0x96, 0x1c, 0xf7, 0x50, 0xdd, 0x07, 0x18, 0x20, 0x4e, 0x01, 0xe2, 0x5d, + 0x40, 0xbc, 0x83, 0x3f, 0xb0, 0x01, 0x9c, 0xb2, 0x88, 0x77, 0xb9, 0xed, 0xf5, 0x6d, 0xff, 0x90, + 0xc2, 0x8b, 0x5b, 0xff, 0x81, 0x66, 0xd1, 0xf4, 0x95, 0xcc, 0x7a, 0xce, 0xe1, 0x97, 0x1c, 0xd0, + 0x12, 0xe9, 0x53, 0x11, 0x43, 0x1f, 0xe3, 0x63, 0x17, 0x06, 0xb2, 0x6f, 0xc7, 0xd0, 0xfc, 0x06, + 0x35, 0x54, 0x1b, 0xa9, 0x98, 0xf7, 0x6e, 0x8d, 0xe6, 0xf8, 0x20, 0x4d, 0xd8, 0x80, 0x09, 0x37, + 0xf3, 0x7b, 0xf7, 0xbe, 0x0f, 0xf2, 0x37, 0xf1, 0xf2, 0xd1, 0xc9, 0x34, 0xce, 0x01, 0xc8, 0x28, + 0x9f, 0xb5, 0x2e, 0xd3, 0x2c, 0x58, 0x5d, 0xb8, 0xcb, 0x13, 0xb6, 0x46, 0x35, 0xb3, 0xa2, 0x1e, + 0x5b, 0xca, 0xf0, 0x88, 0x08, 0xbc, 0x8d, 0xa6, 0xf2, 0x61, 0xd2, 0x0f, 0xae, 0xa3, 0x6b, 0x97, + 0x7c, 0xd0, 0x5c, 0x94, 0x0a, 0x6c, 0xbc, 0xea, 0x22, 0xa6, 0x22, 0x3c, 0x08, 0x0b, 0x04, 0xfc, + 0x09, 0x3a, 0xdd, 0xe5, 0x09, 0x83, 0xf3, 0x76, 0xcc, 0x15, 0x8b, 0x8c, 0x54, 0x87, 0xde, 0xdd, + 0xaf, 0x02, 0xf0, 0x2b, 0xf8, 0x65, 0x70, 0x4f, 0xff, 0x3a, 0x4e, 0xff, 0x2c, 0xb5, 0xaf, 0xc1, + 0x62, 0x02, 0xdc, 0x41, 0x88, 0x0b, 0x94, 0x8d, 0x1c, 0xa4, 0xf9, 0x75, 0x0d, 0xd5, 0xef, 0xda, + 0xa9, 0xd3, 0x5f, 0xd7, 0xbf, 0xd4, 0xd0, 0x4b, 0x50, 0x07, 0x94, 0xec, 0xd9, 0x38, 0x28, 0xdf, + 0xb9, 0xfd, 0x79, 0xc6, 0x14, 0x67, 0x36, 0x3d, 0x8c, 0x2f, 0xd6, 0x57, 0x17, 0xf2, 0x86, 0xed, + 0xd1, 0x76, 0xc8, 0x3e, 0xcf, 0x98, 0x36, 0x6b, 0xef, 0x80, 0x2a, 0xd7, 0xf1, 0x4a, 0xab, 0x74, + 0x0e, 0xcf, 0x64, 0x95, 0xe2, 0x5a, 0x67, 0x50, 0xc3, 0xb7, 0x4a, 0x7c, 0xc8, 0xcd, 0x3a, 0x08, + 0x2f, 0x56, 0x64, 0x96, 0xdc, 0x8f, 0x1c, 0x73, 0xf3, 0xc7, 0xb5, 0x7c, 0xd0, 0xde, 0xb4, 0x3d, + 0xa4, 0xc6, 0x0c, 0x4d, 0x17, 0x2e, 0x06, 0xfa, 0x54, 0x96, 0x85, 0x8e, 0xc4, 0x0d, 0x13, 0x1d, + 0x46, 0x22, 0x99, 0xf8, 0x69, 0xba, 0x58, 0x2d, 0xf9, 0x40, 0x72, 0x9b, 0x43, 0xd3, 0x67, 0x9a, + 0x95, 0x3e, 0x1c, 0x84, 0x25, 0x32, 0x7e, 0x54, 0x76, 0xa9, 0x63, 0xd0, 0x40, 0xbe, 0x05, 0x42, + 0x56, 0xf0, 0x52, 0xcb, 0x36, 0xa3, 0x91, 0x82, 0x27, 0xb7, 0x28, 0x79, 0x87, 0x6a, 0x47, 0x75, + 0x27, 0xd0, 0xfe, 0xa6, 0xdc, 0xc5, 0xe8, 0xb2, 0x39, 0x6d, 0x7e, 0x39, 0x8e, 0xd0, 0x03, 0xca, + 0x13, 0x7f, 0xdd, 0x0c, 0x9d, 0xb0, 0x6a, 0x79, 0x9f, 0x7c, 0x04, 0xf0, 0xf7, 0xf1, 0x96, 0xdb, + 0x6e, 0x58, 0x5d, 0xd9, 0x80, 0xf2, 0x24, 0x6f, 0x96, 0x3a, 0xd0, 0x92, 0x1a, 0xb0, 0x24, 0x20, + 0x5b, 0x5d, 0x98, 0x48, 0x2b, 0xd5, 0xcf, 0x32, 0x40, 0xc5, 0xcc, 0xb4, 0xad, 0xdf, 0xb0, 0xaa, + 0xb5, 0xb4, 0xf8, 0x5d, 0x34, 0xe1, 0xb2, 0x93, 0xf7, 0xc6, 0x57, 0x40, 0xd0, 0x25, 0xfc, 0x62, + 0x9e, 0xdb, 0xbd, 0xef, 0x3f, 0x7e, 0xb0, 0xbb, 0x53, 0xa4, 0x46, 0xcf, 0x82, 0xef, 0x14, 0x1b, + 0x05, 0x48, 0xcf, 0xe3, 0x70, 0x13, 0x97, 0x01, 0xe1, 0x05, 0x7c, 0x1e, 0xd2, 0xf3, 0xf3, 0xec, + 0xf9, 0xc2, 0x00, 0xf2, 0xf4, 0x87, 0x68, 0x76, 0x44, 0x2d, 0x9f, 0x59, 0x0b, 0x2d, 0x6c, 0xea, + 0x81, 0xa4, 0x52, 0xd6, 0x6d, 0x46, 0x32, 0x11, 0x5b, 0x2d, 0x66, 0xec, 0xe1, 0x9e, 0x67, 0xc4, + 0xf7, 0x3d, 0x52, 0x4a, 0xb5, 0x1e, 0x4a, 0x95, 0x37, 0x1e, 0x45, 0xb9, 0xce, 0xcf, 0x9f, 0x43, + 0xb3, 0x25, 0xd3, 0x83, 0xed, 0x78, 0x9a, 0xe6, 0x3f, 0x8e, 0xa1, 0xd9, 0x6d, 0xd9, 0xeb, 0x71, + 0xd1, 0xf3, 0xcf, 0x91, 0xa1, 0x53, 0x32, 0x33, 0x69, 0x66, 0x2a, 0x61, 0xe6, 0x9e, 0xe6, 0x23, + 0x90, 0xb0, 0x81, 0xd7, 0x46, 0xe2, 0xd7, 0x8e, 0x0c, 0x7e, 0x5e, 0xed, 0xf9, 0x28, 0x3b, 0xf2, + 0x2c, 0xee, 0xb3, 0x90, 0x15, 0x8a, 0x70, 0xde, 0xc9, 0x28, 0x82, 0x10, 0xff, 0x0d, 0x7a, 0x51, + 0xb3, 0x94, 0x2a, 0x1b, 0x70, 0x89, 0xec, 0xe9, 0x76, 0xca, 0x54, 0x3b, 0x92, 0x83, 0x54, 0x0a, + 0x26, 0x5c, 0x41, 0x9c, 0x2a, 0x37, 0x02, 0xae, 0xe3, 0xb9, 0x46, 0x18, 0x8d, 0xfa, 0xa4, 0xa0, + 0x72, 0x0e, 0x6f, 0xa5, 0x58, 0xd3, 0x49, 0x8e, 0x07, 0x32, 0x83, 0xb0, 0x91, 0xff, 0xbe, 0x2d, + 0x7b, 0x7a, 0xc7, 0x4e, 0x8d, 0x9e, 0xad, 0xf9, 0xed, 0x34, 0x9a, 0xf0, 0xd6, 0xdf, 0x2d, 0xdd, + 0x7d, 0xea, 0xd8, 0xa1, 0xec, 0x22, 0xa8, 0x70, 0x0e, 0x9f, 0x79, 0xf2, 0xfc, 0x40, 0x56, 0x19, + 0xc0, 0x3e, 0x42, 0x13, 0x2e, 0x5a, 0xe1, 0xee, 0xea, 0xab, 0xa7, 0x3d, 0x4c, 0x75, 0x57, 0xb6, + 0x76, 0x09, 0xb0, 0xce, 0xe3, 0xb3, 0xee, 0xf4, 0xe8, 0x82, 0xc4, 0x23, 0xe0, 0x5d, 0x34, 0xe1, + 0x02, 0x1a, 0x36, 0x09, 0x47, 0xb1, 0xdc, 0xa7, 0x72, 0x8d, 0xef, 0x63, 0x1f, 0x76, 0x57, 0x10, + 0x85, 0x2e, 0xe8, 0x8b, 0x29, 0xd4, 0x63, 0xe1, 0x1d, 0x34, 0xde, 0xda, 0xd9, 0x82, 0x8b, 0xad, + 0xaf, 0x9e, 0xf2, 0x90, 0xc5, 0xfc, 0x56, 0x56, 0xbb, 0xd1, 0x61, 0xda, 0x36, 0x2f, 0x30, 0xaa, + 0xb5, 0x76, 0x2a, 0xe3, 0x4c, 0x68, 0xa1, 0x70, 0x13, 0x8d, 0xdf, 0xdb, 0xdb, 0x82, 0xe0, 0x28, + 0x11, 0x8b, 0x81, 0x29, 0xb4, 0x1f, 0xf1, 0x65, 0x34, 0xb6, 0xde, 0x02, 0xdf, 0xaf, 0xaf, 0xce, + 0xe7, 0x76, 0xf8, 0x8e, 0x31, 0x1c, 0x5b, 0x6f, 0xe1, 0x15, 0x34, 0x95, 0xf7, 0x66, 0xe0, 0xd8, + 0xf5, 0xd5, 0xb3, 0x9e, 0x6c, 0xb4, 0x65, 0x0b, 0x0b, 0x32, 0x7c, 0x03, 0x4d, 0x17, 0x15, 0x0f, + 0x6a, 0x7e, 0x7d, 0xf5, 0x5c, 0xb1, 0x28, 0x18, 0xa9, 0x84, 0x61, 0x49, 0x88, 0x17, 0xd1, 0x49, + 0x48, 0xfa, 0x50, 0xdd, 0xeb, 0xab, 0x38, 0x97, 0x52, 0x16, 0x82, 0xd0, 0x11, 0xe0, 0x61, 0xe5, + 0x8f, 0x15, 0xb0, 0x33, 0x2a, 0xad, 0x2b, 0xce, 0xcb, 0xdc, 0xbb, 0x0e, 0x5a, 0x99, 0x22, 0x9f, + 0x14, 0xeb, 0x2f, 0xd8, 0xe4, 0x10, 0xaa, 0x5d, 0x65, 0x2a, 0xd6, 0x63, 0xc5, 0x62, 0xc7, 0xbb, + 0x69, 0xe5, 0x0f, 0x23, 0xaf, 0xa1, 0x13, 0x36, 0x4f, 0xc2, 0x66, 0xb1, 0xac, 0x36, 0x65, 0xea, + 0x0c, 0xe1, 0x33, 0x0e, 0xd0, 0xa4, 0x0f, 0xe1, 0xc6, 0x79, 0xa0, 0x3c, 0xe3, 0x29, 0x47, 0x02, + 0x3b, 0xcc, 0x89, 0xf0, 0x1d, 0xf0, 0xf1, 0x8e, 0xd4, 0x0c, 0x16, 0x6d, 0x53, 0x65, 0xea, 0xd8, + 0x14, 0xb4, 0x93, 0xc0, 0xae, 0xc1, 0x7e, 0xb5, 0x91, 0x64, 0x19, 0x88, 0x8b, 0x55, 0xe7, 0xdd, + 0xf6, 0x03, 0xfe, 0x6a, 0x0c, 0xcd, 0xd3, 0xcc, 0x48, 0xdb, 0x38, 0xb6, 0x63, 0x39, 0xa0, 0x5c, + 0xc0, 0x86, 0x66, 0x7a, 0xed, 0x57, 0x6e, 0xf7, 0xf8, 0x5d, 0x0d, 0xff, 0xb2, 0xb6, 0x01, 0x1f, + 0x7c, 0xcf, 0x00, 0x9e, 0x93, 0xf3, 0x68, 0xb2, 0x98, 0x30, 0xa3, 0x99, 0x88, 0xd4, 0x61, 0x6a, + 0xae, 0x56, 0x5b, 0xfc, 0x0e, 0x23, 0x8a, 0x69, 0x99, 0xec, 0x83, 0x26, 0xbe, 0x25, 0x28, 0xfa, + 0xcb, 0x7d, 0x4e, 0x6d, 0x0b, 0x17, 0x3c, 0xfc, 0x78, 0x77, 0xf3, 0x16, 0xf1, 0x7f, 0x6c, 0xaa, + 0xec, 0x63, 0x3a, 0xd2, 0x4f, 0x05, 0x76, 0xda, 0xa6, 0xd5, 0x46, 0x1d, 0x52, 0x83, 0xd5, 0xc3, + 0x26, 0x70, 0x4d, 0xde, 0x5e, 0x86, 0xcf, 0x37, 0x6e, 0x5c, 0x27, 0x7f, 0x5e, 0x79, 0xa6, 0xa0, + 0xb2, 0x37, 0x2e, 0xf4, 0xc9, 0x5b, 0x45, 0xa9, 0x06, 0x84, 0xf4, 0x8d, 0x49, 0xf5, 0xad, 0xa5, + 0xa5, 0x23, 0xe6, 0x2f, 0x85, 0x73, 0xf9, 0x89, 0x33, 0x1b, 0x7f, 0x8a, 0x4e, 0x17, 0x34, 0xee, + 0x07, 0x8d, 0xfa, 0xac, 0x71, 0xee, 0xf8, 0x5e, 0xd2, 0x75, 0x2b, 0x39, 0x43, 0x75, 0xa8, 0xd1, + 0x41, 0xb8, 0x90, 0x9f, 0xdb, 0x4e, 0x7e, 0xdd, 0xc2, 0x74, 0x26, 0xe0, 0x85, 0xaf, 0xff, 0x26, + 0x00, 0x00, 0xff, 0xff, 0x8d, 0x35, 0xaf, 0xd9, 0x4d, 0x1d, 0x00, 0x00, } diff --git a/api/proto/config.proto b/api/proto/config.proto index c6bc3b6fce7..c595e15ce23 100644 --- a/api/proto/config.proto +++ b/api/proto/config.proto @@ -199,6 +199,10 @@ message FrontendConfig { string artifacts_path = 7 [(sem_type) = { description: "Path to additional artifacts to load", }]; + + string public_path = 8 [(sem_type) = { + description: "If specified we export this path through the /public/ handler.", + }]; } diff --git a/api/vfs.go b/api/vfs.go index 8870fe306da..9affa3f3b37 100644 --- a/api/vfs.go +++ b/api/vfs.go @@ -84,6 +84,9 @@ func renderDBVFS( filestore_urn := path.Join("clients", client_id, "vfs_files", vfs_path) downloaded_items, err := file_store.GetFileStore(config_obj). ListDirectory(filestore_urn) + if err != nil { + return nil, err + } // We only care about actual files. downloaded_files := []os.FileInfo{} diff --git a/artifacts/artifacts.go b/artifacts/artifacts.go index 80c98d0feac..4d81057c76b 100644 --- a/artifacts/artifacts.go +++ b/artifacts/artifacts.go @@ -24,7 +24,7 @@ import ( ) var ( - artifact_in_query_regex = regexp.MustCompile("Artifact\\.([^\\s\\(]+)\\(") + artifact_in_query_regex = regexp.MustCompile(`Artifact\.([^\s\(]+)\(`) global_repository *Repository mu sync.Mutex ) @@ -97,7 +97,7 @@ func (self *Repository) Set(artifact *artifacts_proto.Artifact) { func (self *Repository) List() []string { result := []string{} - for k, _ := range self.Data { + for k := range self.Data { result = append(result, k) } sort.Strings(result) @@ -130,7 +130,7 @@ func (self *Repository) PopulateArtifactsVQLCollectorArgs( dependencies[dep] = true } } - for k, _ := range dependencies { + for k := range dependencies { artifact, pres := self.Get(k) if pres { // Deliberately make a copy of the artifact - @@ -190,7 +190,6 @@ func Compile(artifact *artifacts_proto.Artifact, }) } - queries := []string{} // The artifact format requires all queries to be LET // queries except for the last one. for idx2, query := range source.Queries { @@ -228,7 +227,6 @@ func Compile(artifact *artifacts_proto.Artifact, VQL: "LET " + query_name + " = " + query, }) - queries = append(queries, query_name) } source_result = query_name } diff --git a/artifacts/plugin.go b/artifacts/plugin.go index 4c978772929..24e4f14d21f 100644 --- a/artifacts/plugin.go +++ b/artifacts/plugin.go @@ -21,7 +21,7 @@ type ArtifactRepositoryPlugin struct { func (self *ArtifactRepositoryPlugin) Print() { var children []string - for k, _ := range self.children { + for k := range self.children { children = append(children, k) } fmt.Printf("prefix '%v', Children %v, Leaf %v\n", @@ -142,7 +142,7 @@ func (self _ArtifactRepositoryPluginAssociativeProtocol) GetMembers( value := _getArtifactRepositoryPlugin(a) if value != nil { - for k, _ := range value.children { + for k := range value.children { result = append(result, k) } } diff --git a/bin/artifacts.go b/bin/artifacts.go index 42b76da18db..7ed23d0d88d 100644 --- a/bin/artifacts.go +++ b/bin/artifacts.go @@ -54,9 +54,7 @@ func listArtifacts() []string { if err != nil { return result } - for _, name := range repository.List() { - result = append(result, name) - } + result = append(result, repository.List()...) return result } @@ -155,6 +153,15 @@ func doArtifactCollect() { kingpin.FatalIfError( err, fmt.Sprintf("Unable to compile artifact %s.", name)) + if env_map != nil { + for k, v := range *env_map { + request.Env = append( + request.Env, &actions_proto.VQLEnv{ + Key: k, Value: v, + }) + } + } + collectArtifact(config_obj, repository, name, request) } } diff --git a/bin/artifacts_acquire.go b/bin/artifacts_acquire.go index ce290563852..764c47db1fb 100644 --- a/bin/artifacts_acquire.go +++ b/bin/artifacts_acquire.go @@ -86,6 +86,9 @@ func acquireArtifact(ctx context.Context, config_obj *api_proto.Config, defer fd.Close() writer, err := csv.GetCSVWriter(scope, fd) + if err != nil { + return err + } defer writer.Close() for _, query := range request.Query { diff --git a/bin/artifacts_hunt.go b/bin/artifacts_hunt.go index 5bd7cb9549d..a44d848dfae 100644 --- a/bin/artifacts_hunt.go +++ b/bin/artifacts_hunt.go @@ -50,6 +50,18 @@ func doArtifactsHunt() { State: api_proto.Hunt_RUNNING, } + if artifact_command_hunt_condition != nil { + hunt_request.Condition = &api_proto.HuntCondition{} + hunt_request.Condition.GetGenericCondition(). + FlowConditionQuery = &actions_proto.VQLCollectorArgs{ + Query: []*actions_proto.VQLRequest{ + &actions_proto.VQLRequest{ + VQL: *artifact_command_hunt_condition, + }, + }, + } + } + // Just start an artifact collector hunt using the gRPC API. config_obj := get_config_or_default() channel := grpc_client.GetChannel(config_obj) diff --git a/bin/config.go b/bin/config.go index 97f17998dd1..bd665528131 100644 --- a/bin/config.go +++ b/bin/config.go @@ -36,7 +36,7 @@ func doShowConfig() { // Dump out the embedded config as is. if *config_path == "" { content := string(config.FileConfigDefaultYaml) - content = regexp.MustCompile("##[^\\n]+\\n").ReplaceAllString(content, "") + content = regexp.MustCompile(`##[^\n]+\n`).ReplaceAllString(content, "") fmt.Printf("%v", content) return } @@ -129,16 +129,16 @@ func doDumpClientConfig() { func init() { command_handlers = append(command_handlers, func(command string) bool { switch command { - case "config show": + case config_show_command.FullCommand(): doShowConfig() - case "config generate": + case config_generate_command.FullCommand(): doGenerateConfig() - case "config rotate_key": + case config_rotate_server_key.FullCommand(): doRotateKeyConfig() - case "config client": + case config_client_command.FullCommand(): doDumpClientConfig() default: return false diff --git a/bin/installer_windows.go b/bin/installer_windows.go index 51795327d51..1c3a54461e5 100644 --- a/bin/installer_windows.go +++ b/bin/installer_windows.go @@ -50,7 +50,7 @@ var ( "run", "Run as a service - only called by service manager.").Hidden() ) -func doInstall() error { +func doInstall() (err error) { config_obj, err := config.LoadClientConfig(*config_path) if err != nil { return errors.Wrap(err, "Unable to load config file") @@ -62,7 +62,22 @@ func doInstall() error { target_path := os.ExpandEnv(config_obj.Client.WindowsInstaller.InstallPath) executable, err := os.Executable() - kingpin.FatalIfError(err, "Can't get executable path") + if err != nil { + return err + } + + // Since we stopped the service here, we need to make sure it + // is started again. + defer func() { + err = startService(service_name) + + // We can not start the service - everything is messed + // up! Just die here. + if err != nil { + return + } + logger.Info("Started service %s", service_name) + }() pres, err := checkServiceExists(service_name) if err != nil { @@ -79,18 +94,6 @@ func doInstall() error { } } - // Since we stopped the service here, we need to make sure it - // is started again. - defer func() { - err = startService(service_name) - - // We can not start the service - everything is messed - // up! Just die here. - kingpin.FatalIfError(err, "Start service") - - logger.Info("Started service %s", service_name) - }() - // Try to copy the executable to the target_path. err = utils.CopyFile(executable, target_path, 0755) if err != nil && os.IsNotExist(errors.Cause(err)) { @@ -399,7 +402,16 @@ func init() { var err error switch command { case "service install": - err = doInstall() + // Try 10 times to install the service. + for i := 0; i < 10; i++ { + err = doInstall() + if err == nil { + break + } + + time.Sleep(10 * time.Second) + } + case "service remove": doRemove() diff --git a/bin/pool.go b/bin/pool.go index d9e5ce10928..e7e38764b74 100644 --- a/bin/pool.go +++ b/bin/pool.go @@ -88,10 +88,7 @@ func doPoolClient() { } // Block forever. - select { - case <-ctx.Done(): - break - } + <-ctx.Done() } func init() { diff --git a/bin/repack.go b/bin/repack.go index ae3cf8e49b1..d369b33b22b 100644 --- a/bin/repack.go +++ b/bin/repack.go @@ -1,10 +1,11 @@ package main import ( - "gopkg.in/alecthomas/kingpin.v2" "io/ioutil" "os" "regexp" + + "gopkg.in/alecthomas/kingpin.v2" "www.velocidex.com/golang/velociraptor/config" ) @@ -23,7 +24,7 @@ var ( "output", "The filename to write the repacked binary."). Required().String() - embedded_re = regexp.MustCompile("#{3}\\n") + embedded_re = regexp.MustCompile(`#{3}\n`) ) func doRepack() { diff --git a/bin/shell.go b/bin/shell.go index b0fae1e8a42..641e20d391d 100644 --- a/bin/shell.go +++ b/bin/shell.go @@ -152,7 +152,6 @@ func get_responses(ctx context.Context, print_value(row, "Stderr") print_value(row, "Stdout") - return } } diff --git a/bin/utils.go b/bin/utils.go index dcb8bd0a95a..0723d8a399d 100644 --- a/bin/utils.go +++ b/bin/utils.go @@ -4,25 +4,10 @@ import ( "context" "os" "os/signal" - "strings" vfilter "www.velocidex.com/golang/vfilter" ) -func hard_wrap(text string, colBreak int) string { - text = strings.TrimSpace(text) - wrapped := "" - var i int - for i = 0; len(text[i:]) > colBreak; i += colBreak { - - wrapped += text[i:i+colBreak] + "\n" - - } - wrapped += text[i:] - - return wrapped -} - func InstallSignalHandler( scope *vfilter.Scope) context.Context { diff --git a/bin/version.go b/bin/version.go index cf6b27e4d45..5d71d97faa9 100644 --- a/bin/version.go +++ b/bin/version.go @@ -14,7 +14,7 @@ var ( func init() { command_handlers = append(command_handlers, func(command string) bool { - if command == "version" { + if command == version.FullCommand() { config_obj := config.GetDefaultConfig() res, err := yaml.Marshal(config_obj.Version) if err != nil { diff --git a/bin/vql.go b/bin/vql.go index 7ad3464756f..b24799be6ec 100644 --- a/bin/vql.go +++ b/bin/vql.go @@ -68,7 +68,7 @@ func doVQLList() { func init() { command_handlers = append(command_handlers, func(command string) bool { switch command { - case "vql list": + case vql_info_list.FullCommand(): doVQLList() default: return false diff --git a/config/config.go b/config/config.go index c62b25bafd1..71a8d50332b 100644 --- a/config/config.go +++ b/config/config.go @@ -87,7 +87,7 @@ func GetDefaultConfig() *api_proto.Config { // connect to. BindAddress: "0.0.0.0", BindPort: 8000, - ClientLeaseTime: 600, + ClientLeaseTime: 60000, }, Datastore: &api_proto.DatastoreConfig{ Implementation: "FileBaseDataStore", diff --git a/datastore/datastore.go b/datastore/datastore.go index 97722d6cc08..153f40ab656 100644 --- a/datastore/datastore.go +++ b/datastore/datastore.go @@ -94,7 +94,7 @@ func GetImpl(name string) (DataStore, bool) { func GetDB(config_obj *api_proto.Config) (DataStore, error) { db, pres := GetImpl(config_obj.Datastore.Implementation) if !pres { - return nil, errors.New("No datastore implementation") + return nil, errors.New("no datastore implementation") } return db, nil diff --git a/datastore/filebased.go b/datastore/filebased.go index 4c146e48cde..bae50d2e624 100644 --- a/datastore/filebased.go +++ b/datastore/filebased.go @@ -345,7 +345,7 @@ func (self *FileBaseDataStore) SearchClients( add_func(query) } - for k, _ := range seen { + for k := range seen { result = append(result, k) } diff --git a/file_store/csv/reader.go b/file_store/csv/reader.go index 10a3f701795..e4d6d735aa6 100644 --- a/file_store/csv/reader.go +++ b/file_store/csv/reader.go @@ -75,7 +75,6 @@ import ( "errors" "fmt" "io" - "os" "strconv" "strings" "unicode" @@ -107,7 +106,7 @@ var ( ErrBareQuote = errors.New("bare \" in non-quoted-field") ErrQuote = errors.New("extraneous or missing \" in quoted-field") ErrFieldCount = errors.New("wrong number of fields") - ErrNoLineFeed = errors.New("Line does not end with line feed.") + ErrNoLineFeed = errors.New("line does not end with line feed") ) var errInvalidDelim = errors.New("csv: invalid field or comment delimiter") @@ -284,7 +283,7 @@ func (r *Reader) ReadAny() ([]interface{}, error) { } func (r *Reader) Seek(offset int64) { - r.raw_reader.Seek(offset, os.SEEK_SET) + r.raw_reader.Seek(offset, io.SeekStart) r.r = bufio.NewReader(r.raw_reader) r.ByteOffset = offset } diff --git a/file_store/csv/reader_test.go b/file_store/csv/reader_test.go index 67e176f3dbe..dcb9b274b75 100644 --- a/file_store/csv/reader_test.go +++ b/file_store/csv/reader_test.go @@ -5,7 +5,6 @@ package csv import ( - "io" "reflect" "strings" "testing" @@ -502,29 +501,3 @@ x,,, }) } } - -// nTimes is an io.Reader which yields the string s n times. -type nTimes struct { - s string - n int - off int -} - -func (r *nTimes) Read(p []byte) (n int, err error) { - for { - if r.n <= 0 || r.s == "" { - return n, io.EOF - } - n0 := copy(p, r.s[r.off:]) - p = p[n0:] - n += n0 - r.off += n0 - if r.off == len(r.s) { - r.off = 0 - r.n-- - } - if len(p) == 0 { - return - } - } -} diff --git a/file_store/csv/utils.go b/file_store/csv/utils.go index fd077a12a43..966a587045e 100644 --- a/file_store/csv/utils.go +++ b/file_store/csv/utils.go @@ -72,9 +72,9 @@ func GetCSVWriter(scope *vfilter.Scope, fd file_store.WriteSeekCloser) (*CSVWrit return nil, err } headers_written := length > 0 + result.wg.Add(1) go func() { - result.wg.Add(1) defer result.wg.Done() w := NewWriter(fd) diff --git a/file_store/csv/writer.go b/file_store/csv/writer.go index 2f4524f0c7f..c4711281bb9 100644 --- a/file_store/csv/writer.go +++ b/file_store/csv/writer.go @@ -25,7 +25,7 @@ var ( "^[+-]?[0-9]+$") protected_prefix = regexp.MustCompile( - "^( |\\{|\\[|true|false|base64:)") + `^( |\{|\[|true|false|base64:)`) ) // A Writer writes records to a CSV encoded file. diff --git a/file_store/file_store.go b/file_store/file_store.go index 39ab79cbb73..39a5d505602 100644 --- a/file_store/file_store.go +++ b/file_store/file_store.go @@ -111,7 +111,7 @@ func (self *DirectoryFileStore) WriteFile(filename string) (WriteSeekCloser, err func (self *DirectoryFileStore) FilenameToFileStorePath(filename string) ( string, error) { if self.config_obj.Datastore.FilestoreDirectory == "" { - return "", errors.New("No configured file store directory.") + return "", errors.New("no configured file store directory") } components := []string{self.config_obj.Datastore.FilestoreDirectory} @@ -130,11 +130,11 @@ func (self *DirectoryFileStore) FilenameToFileStorePath(filename string) ( func (self *DirectoryFileStore) FileStorePathToFilename(filename string) ( string, error) { if self.config_obj.Datastore.FilestoreDirectory == "" { - return "", errors.New("No configured file store directory.") + return "", errors.New("no configured file store directory") } if !strings.HasPrefix(filename, self.config_obj.Datastore.FilestoreDirectory) { - return "", errors.New("Not a file store directory.") + return "", errors.New("not a file store directory") } components := []string{} diff --git a/flows/artifacts.go b/flows/artifacts.go index 4ca62492d10..0c36dbff7a8 100644 --- a/flows/artifacts.go +++ b/flows/artifacts.go @@ -132,6 +132,10 @@ func (self *ArtifactCollector) ProcessMessage( defer fd.Close() writer, err := csv.GetCSVWriter(vql_subsystem.MakeScope(), fd) + if err != nil { + fmt.Printf("Error: %v\n", err) + return err + } defer writer.Close() // Decode the JSON data. diff --git a/flows/events.go b/flows/events.go index 4db2d8af941..e4b3f455976 100644 --- a/flows/events.go +++ b/flows/events.go @@ -90,6 +90,9 @@ func (self *JournalWriter) WriteEvent(event *Event) error { defer scope.Close() writer, err := csv.GetCSVWriter(scope, fd) + if err != nil { + return err + } defer writer.Close() // Decode the VQLResponse and write into the CSV file. @@ -104,8 +107,7 @@ func (self *JournalWriter) WriteEvent(event *Event) error { Set("ClientId", event.ClientId) for _, column := range event.Columns { - item, _ := row[column] - csv_row.Set(column, item) + csv_row.Set(column, row[column]) } writer.Write(csv_row) } @@ -205,6 +207,10 @@ func (self *MonitoringFlow) ProcessMessage( defer fd.Close() writer, err := csv.GetCSVWriter(vql_subsystem.MakeScope(), fd) + if err != nil { + fmt.Printf("Error: %v\n", err) + return err + } defer writer.Close() var rows []map[string]interface{} @@ -216,8 +222,7 @@ func (self *MonitoringFlow) ProcessMessage( for _, row := range rows { csv_row := vfilter.NewDict() for _, column := range response.Columns { - item, _ := row[column] - csv_row.Set(column, item) + csv_row.Set(column, row[column]) } writer.Write(csv_row) diff --git a/flows/file_finder.go b/flows/file_finder.go index 57a52c198df..eb62c4bc8e0 100644 --- a/flows/file_finder.go +++ b/flows/file_finder.go @@ -28,7 +28,7 @@ func (self *FileFinder) Start( args proto.Message) error { file_finder_args, ok := args.(*flows_proto.FileFinderArgs) if !ok { - return errors.New("Expected args of type VInterrogateArgs") + return errors.New("expected args of type VInterrogateArgs") } builder := file_finder_builder{args: file_finder_args} @@ -57,10 +57,9 @@ func (self *FileFinder) Start( } type file_finder_builder struct { - args *flows_proto.FileFinderArgs - columns []string - glob_plugin string - result actions_proto.VQLCollectorArgs + args *flows_proto.FileFinderArgs + columns []string + result actions_proto.VQLCollectorArgs } // Returns a list of conditions which are expensive to execute (such as grep). @@ -150,7 +149,7 @@ func (self *file_finder_builder) compileGlobFunction() (string, error) { glob_vars := []string{} if len(self.args.Paths) == 0 { - return "", errors.New("Invalid request: No globs specified.") + return "", errors.New("invalid request: No globs specified") } // Push the glob into the query environment to prevent // escaping issues. @@ -250,7 +249,7 @@ func processCondition(condition *flows_proto.FileFinderCondition) ([]string, err if mod_time.MinLastModifiedTime > mod_time.MaxLastModifiedTime && mod_time.MaxLastModifiedTime != 0 { return nil, errors.New( - "Invalid modification time condition: min > max") + "invalid modification time condition: min > max") } if mod_time.MinLastModifiedTime != 0 { @@ -269,7 +268,7 @@ func processCondition(condition *flows_proto.FileFinderCondition) ([]string, err if access_time.MinLastAccessTime > access_time.MaxLastAccessTime && access_time.MaxLastAccessTime != 0 { return nil, errors.New( - "Invalid access time condition: min > max") + "invalid access time condition: min > max") } if access_time.MinLastAccessTime != 0 { @@ -288,7 +287,7 @@ func processCondition(condition *flows_proto.FileFinderCondition) ([]string, err if inode_time.MinLastInodeChangeTime > inode_time.MaxLastInodeChangeTime && inode_time.MaxLastInodeChangeTime != 0 { return nil, errors.New( - "Invalid inode change time condition: min > max") + "invalid inode change time condition: min > max") } if inode_time.MinLastInodeChangeTime != 0 { @@ -306,7 +305,7 @@ func processCondition(condition *flows_proto.FileFinderCondition) ([]string, err if size != nil { if size.MinFileSize > size.MaxFileSize && size.MaxFileSize != 0 { return nil, errors.New( - "Invalid size condition: min > max") + "invalid size condition: min > max") } if size.MinFileSize != 0 { result = append(result, fmt.Sprintf( diff --git a/flows/fixtures/compileFileFinderArgs.golden b/flows/fixtures/compileFileFinderArgs.golden index 67fd2c74418..2459c7c8857 100644 --- a/flows/fixtures/compileFileFinderArgs.golden +++ b/flows/fixtures/compileFileFinderArgs.golden @@ -1,7 +1,7 @@ [ { "Name": "Empty request", - "Error": "Invalid request: No globs specified.", + "Error": "invalid request: No globs specified", "Request": {}, "CollectorArgs": null }, @@ -113,7 +113,7 @@ }, { "Name": "Mod time Error", - "Error": "Invalid modification time condition: min \u003e max", + "Error": "invalid modification time condition: min \u003e max", "Request": { "paths": [ "/bin/*" diff --git a/flows/foreman.go b/flows/foreman.go index 0c26f7dae5a..d73810e6b75 100644 --- a/flows/foreman.go +++ b/flows/foreman.go @@ -132,11 +132,12 @@ func (self *Foreman) ProcessMessage( return nil } - // Check for labels. - label_condition := hunt.Condition.GetLabels() - if label_condition != nil && len(label_condition.Label) > 0 { - // TODO - } + // TODO Check for labels. + /* + label_condition := hunt.Condition.GetLabels() + if label_condition != nil && len(label_condition.Label) > 0 { + } + */ flow_condition_query, err := calculateFlowConditionQuery(hunt) if err != nil { diff --git a/flows/generic.go b/flows/generic.go index b62b8911e61..7fd33beb0db 100644 --- a/flows/generic.go +++ b/flows/generic.go @@ -36,7 +36,7 @@ func (self *VQLCollector) Start( args proto.Message) error { vql_collector_args, ok := args.(*actions_proto.VQLCollectorArgs) if !ok { - return errors.New("Expected args of type VQLCollectorArgs") + return errors.New("expected args of type VQLCollectorArgs") } // Add any required artifacts to the request. diff --git a/flows/hunts.go b/flows/hunts.go index 27dcd4e8fde..574764c32c5 100644 --- a/flows/hunts.go +++ b/flows/hunts.go @@ -199,6 +199,10 @@ func ModifyHunt(config_obj *api_proto.Config, hunt_modification *api_proto.Hunt) // Write the new hunt object to the datastore. db, err := datastore.GetDB(config_obj) + if err != nil { + return err + } + err = db.SetSubject(config_obj, hunt.HuntId, hunt) if err != nil { return err diff --git a/flows/interrogate.go b/flows/interrogate.go index 57960e4df8c..6cbfcddf56b 100644 --- a/flows/interrogate.go +++ b/flows/interrogate.go @@ -1,4 +1,3 @@ -// package flows import ( @@ -41,15 +40,11 @@ func (self *VInterrogate) Start( } vql_request := &actions_proto.VQLCollectorArgs{} - - for _, q := range interrogate_args.Queries { - vql_request.Query = append(vql_request.Query, q) - } + vql_request.Query = append(vql_request.Query, interrogate_args.Queries...) // Run custom queries from the config file if present. - for _, q := range config_obj.Flows.InterrogateAdditionalQueries { - vql_request.Query = append(vql_request.Query, q) - } + vql_request.Query = append(vql_request.Query, + config_obj.Flows.InterrogateAdditionalQueries...) // Run standard queries. queries := []*actions_proto.VQLRequest{ @@ -68,9 +63,7 @@ func (self *VInterrogate) Start( Name: "Recent Users"}, } - for _, query := range queries { - vql_request.Query = append(vql_request.Query, query) - } + vql_request.Query = append(vql_request.Query, queries...) // Add any required artifacts to the request. repository, err := artifacts.GetGlobalRepository(config_obj) diff --git a/flows/utils.go b/flows/utils.go index 5803fcb4557..acbf0b9f814 100644 --- a/flows/utils.go +++ b/flows/utils.go @@ -42,6 +42,9 @@ func QueueAndNotifyClient( config_obj, client_id, flow_urn, client_action_name, message, next_state) + if err != nil { + return err + } channel := grpc_client.GetChannel(config_obj) defer channel.Close() diff --git a/glob/accessor_linux.go b/glob/accessor_linux.go index 1bf8ca4736b..cd7fa73e925 100644 --- a/glob/accessor_linux.go +++ b/glob/accessor_linux.go @@ -79,31 +79,15 @@ func (self *OSFileInfo) MarshalJSON() ([]byte, error) { return result, err } -func (u *OSFileInfo) UnmarshalJSON(data []byte) error { +func (self *OSFileInfo) UnmarshalJSON(data []byte) error { return nil } // Real implementation for non windows OSs: -type OSFileSystemAccessor struct { - fd_cache map[string]*os.File -} +type OSFileSystemAccessor struct{} func (self OSFileSystemAccessor) New(ctx context.Context) FileSystemAccessor { - result := &OSFileSystemAccessor{ - fd_cache: make(map[string]*os.File), - } - - // When the context is done, close all the files. The files - // must remain open until the entire VQL query is done. - go func() { - select { - case <-ctx.Done(): - for _, v := range result.fd_cache { - v.Close() - } - } - }() - + result := &OSFileSystemAccessor{} return result } @@ -131,18 +115,11 @@ func (self OSFileSystemAccessor) ReadDir(path string) ([]FileInfo, error) { } func (self OSFileSystemAccessor) Open(path string) (ReadSeekCloser, error) { - fd, pres := self.fd_cache[path] - if pres { - return fd, nil - } - file, err := os.Open(path) if err != nil { return nil, err } - self.fd_cache[path] = file - return file, nil } diff --git a/glob/factory.go b/glob/factory.go index 24e05238c04..fc84382c42e 100644 --- a/glob/factory.go +++ b/glob/factory.go @@ -8,8 +8,7 @@ import ( ) var ( - scheme_regex = regexp.MustCompile("^([a-z]+):(.+)$") - handlers map[string]FileSystemAccessor + handlers map[string]FileSystemAccessor ) // Interface for accessing the filesystem. Used for dependency diff --git a/glob/glob.go b/glob/glob.go index f822e73e527..ea6e708ce1e 100644 --- a/glob/glob.go +++ b/glob/glob.go @@ -56,7 +56,6 @@ func (self _Sentinel) String() string { var ( sentinal_filter = _Sentinel{} - sentinal = &Globber{sentinal_filter: nil} ) type _RecursiveComponent struct { @@ -345,12 +344,10 @@ func (self Globber) _expand_path_components(filter []_PathFilterer, depth int) e } var ( - _INTERPOLATED_REGEX = regexp.MustCompile("%%([^%]+?)%%") - // Support Brace Expansion {a,b}. NOTE: This happens before wild card // expansions so you can do /foo/bar/{*.exe,*.dll} _GROUPING_PATTERN = regexp.MustCompile("^(.*){([^}]+)}(.*)$") - _RECURSION_REGEX = regexp.MustCompile("\\*\\*(\\d*)") + _RECURSION_REGEX = regexp.MustCompile(`\*\*(\d*)`) // A regex indicating if there are shell globs in this path. _GLOB_MAGIC_CHECK = regexp.MustCompile("[*?[]") diff --git a/http_comms/comms.go b/http_comms/comms.go index e3508345403..1aa9cd84f5d 100644 --- a/http_comms/comms.go +++ b/http_comms/comms.go @@ -29,12 +29,11 @@ import ( // be done too frequently and should only be done in response for the // 406 HTTP codes. type Enroller struct { - config_obj *api_proto.Config - manager *crypto.CryptoManager - executor executor.Executor - logger *logging.LogContext - last_enrollment_time time.Time - last_foreman_check_time time.Time + config_obj *api_proto.Config + manager *crypto.CryptoManager + executor executor.Executor + logger *logging.LogContext + last_enrollment_time time.Time } // TODO: This is a hold over from GRR - do we need it? GRR's @@ -206,10 +205,8 @@ func (self *HTTPConnector) ReKeyNextServer() { if self.current_url_idx == 0 { self.logger.Info("Waiting for a reachable server: %v", self.maxPoll) - select { - case <-time.After(self.maxPoll): - continue - } + + <-time.After(self.maxPoll) } } } @@ -471,10 +468,7 @@ func (self *Sender) Start(ctx context.Context) { // (since the executor channel itself has no // buffer). if atomic.LoadInt32(&self.IsPaused) != 0 { - select { - case <-time.After(self.minPoll): - continue - } + <-time.After(self.minPoll) } else { select { case <-ctx.Done(): @@ -602,10 +596,7 @@ func (self *HTTPCommunicator) Run(ctx context.Context) { self.receiver.Start(ctx) self.sender.Start(ctx) - select { - case <-ctx.Done(): - return - } + <-ctx.Done() } func NewHTTPCommunicator( diff --git a/server/comms.go b/server/comms.go index 7c2f963c23f..23c4df165c1 100644 --- a/server/comms.go +++ b/server/comms.go @@ -32,6 +32,14 @@ func PrepareFrontendMux( router.Handle("/server.pem", server_pem(config_obj)) router.Handle("/control", control(server_obj)) router.Handle("/reader", reader(config_obj, server_obj)) + + if config_obj.Frontend.PublicPath != "" { + router.Handle( + "/public/", http.StripPrefix("/public/", + http.FileServer(http.Dir( + config_obj.Frontend.PublicPath, + )))) + } } // Starts the frontend over HTTP. Velociraptor uses its own encryption @@ -81,8 +89,9 @@ func InstallSignalHandler( // server. quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt) + wg.Add(1) + go func() { - wg.Add(1) defer wg.Done() // Start all the services and shut them down when we diff --git a/server/flows.go b/server/flows.go index 37c83448b3d..7884c58ebd8 100644 --- a/server/flows.go +++ b/server/flows.go @@ -17,7 +17,7 @@ func enroll(server *Server, message *crypto_proto.GrrMessage) error { csr, pres := responder.ExtractGrrMessagePayload( message).(*crypto_proto.Certificate) if !pres { - return errors.New("Request should be of type Certificate") + return errors.New("request should be of type Certificate") } if csr.GetType() == crypto_proto.Certificate_CSR && csr.Pem != nil { diff --git a/server/server.go b/server/server.go index 4aa7794cf14..a7a4136d303 100644 --- a/server/server.go +++ b/server/server.go @@ -97,8 +97,6 @@ type Server struct { logger *logging.LogContext db datastore.DataStore NotificationPool *NotificationPool - - mu sync.Mutex } func (self *Server) Close() { @@ -197,27 +195,17 @@ func (self *Server) Process( return nil, 0, errors.WithStack(err) } - // Here we split incoming messages from Velociraptor clients - // and GRR clients. We process the Velociraptor clients - // ourselves, while relaying the GRR client's messages to the - // GRR frontend server. - var grr_messages []*crypto_proto.GrrMessage - var velociraptor_messages []*crypto_proto.GrrMessage - + var messages []*crypto_proto.GrrMessage for _, message := range message_list.Job { if message_info.Authenticated { message.AuthState = crypto_proto.GrrMessage_AUTHENTICATED } message.Source = message_info.Source - if message.ClientType == crypto_proto.GrrMessage_VELOCIRAPTOR { - velociraptor_messages = append(velociraptor_messages, message) - } else { - grr_messages = append(grr_messages, message) - } + messages = append(messages, message) } err = self.processVelociraptorMessages( - ctx, message_info.Source, velociraptor_messages) + ctx, message_info.Source, messages) if err != nil { return nil, 0, err } @@ -238,10 +226,9 @@ func (self *Server) Process( message_list = &crypto_proto.MessageList{} if drain_requests_for_client { - for _, response := range self.DrainRequestsForClient( - message_info.Source) { - message_list.Job = append(message_list.Job, response) - } + message_list.Job = append( + message_list.Job, + self.DrainRequestsForClient(message_info.Source)...) } response, err := self.manager.EncryptMessageList( diff --git a/services/hunt_dispatcher.go b/services/hunt_dispatcher.go index 22083989102..47dcc2f43fa 100644 --- a/services/hunt_dispatcher.go +++ b/services/hunt_dispatcher.go @@ -16,7 +16,7 @@ import ( var ( global_hunt_dispatcher *HuntDispatcher - hunt_id_regex = regexp.MustCompile("^H\\.[^.]+$") + hunt_id_regex = regexp.MustCompile(`^H\.[^.]+$`) ) func GetHuntDispatcher() *HuntDispatcher { @@ -82,7 +82,7 @@ func (self *HuntDispatcher) ModifyHunt( hunt_obj, pres := self.hunts[path.Base(hunt_id)] if !pres { - return errors.New("Not found") + return errors.New("not found") } err := cb(hunt_obj) diff --git a/services/hunts.go b/services/hunt_manager.go similarity index 97% rename from services/hunts.go rename to services/hunt_manager.go index 501c1c368c5..dc8228b1d7c 100644 --- a/services/hunts.go +++ b/services/hunt_manager.go @@ -34,7 +34,6 @@ type HuntManager struct { writers map[string]*csv.CSVWriter wg sync.WaitGroup done chan bool - scope *vfilter.Scope config_obj *api_proto.Config } @@ -61,9 +60,9 @@ func (self *HuntManager) Start() error { if err != nil { return err } + self.wg.Add(1) go func() { - self.wg.Add(1) defer self.wg.Done() ctx, cancel := context.WithCancel(context.Background()) @@ -144,7 +143,7 @@ func (self *HuntManager) ProcessRow( // Ignore stopped hunts. if hunt_obj.Stats.Stopped || hunt_obj.State != api_proto.Hunt_RUNNING { - return errors.New("Hunt is stopped") + return errors.New("hunt is stopped") } // Hunt limit exceeded or it expired - we stop it. @@ -154,7 +153,7 @@ func (self *HuntManager) ProcessRow( // Stop the hunt. hunt_obj.Stats.Stopped = true - return errors.New("Hunt is expired") + return errors.New("hunt is expired") } // Use hunt information to launch the flow diff --git a/staticcheck.conf b/staticcheck.conf new file mode 100644 index 00000000000..f7f98c70cb3 --- /dev/null +++ b/staticcheck.conf @@ -0,0 +1,6 @@ +checks = ["all", + "-ST1006", + "-ST1003", + # at least one file in a package should have a package comment + "-ST1000", + ] \ No newline at end of file diff --git a/vql/binary.go b/vql/binary.go index a0f6ad04a8a..c830dab1844 100644 --- a/vql/binary.go +++ b/vql/binary.go @@ -130,16 +130,15 @@ func (self _BinaryParserPlugin) Call( // objects which may reference the file. These objects // may participate in WHERE clause and so will be // referenced after the plugin is terminated. + + // This is a real bad strategy. We should ensure that + // we are taking a copy of file content here! This + // leaks if the VQL is long. go func() { - for { - select { - case <-ctx.Done(): - fd, ok := file.(io.Closer) - if ok { - fd.Close() - } - return - } + <-ctx.Done() + fd, ok := file.(io.Closer) + if ok { + fd.Close() } }() diff --git a/vql/common/yara.go b/vql/common/yara.go index 8262422c8ab..9b4489a5875 100644 --- a/vql/common/yara.go +++ b/vql/common/yara.go @@ -95,9 +95,12 @@ func (self YaraScanPlugin) Call( } accessor := glob.GetAccessor(arg.Accessor, ctx) - number_of_hits := int64(0) buf := make([]byte, arg.Blocksize) + + scan_file: for _, filename := range arg.Files { + // Total hits per file. + number_of_hits := int64(0) f, err := accessor.Open(filename) if err != nil { scope.Log("Failed to open %v", filename) @@ -161,7 +164,7 @@ func (self YaraScanPlugin) Call( number_of_hits += 1 if number_of_hits > arg.NumberOfHits { f.Close() - return + continue scan_file } output_chan <- res } @@ -217,6 +220,11 @@ func (self YaraProcPlugin) Call( go func() { defer close(output_chan) + // Do we need to throttle? + // We count an op as one MB scanned. + any_throttle, _ := scope.Resolve("$throttle") + throttle, _ := any_throttle.(chan time.Time) + arg := &YaraProcPluginArgs{} err := vfilter.ExtractArgs(scope, args, arg) if err != nil { @@ -243,6 +251,10 @@ func (self YaraProcPlugin) Call( output_chan <- match } + // Throttle if needed. + if throttle != nil { + <-throttle + } }() return output_chan diff --git a/vql/filesystem/path.go b/vql/filesystem/path.go index da8f1b7753f..d35671a52f0 100644 --- a/vql/filesystem/path.go +++ b/vql/filesystem/path.go @@ -8,7 +8,7 @@ import ( "www.velocidex.com/golang/vfilter" ) -var basename_regexp = regexp.MustCompile("([^/\\\\]+)$") +var basename_regexp = regexp.MustCompile(`([^/\\]+)$`) type _BasenameArgs struct { Path string `vfilter:"required,field=path"` diff --git a/vql/filesystem/tempfile.go b/vql/filesystem/tempfile.go index de49056cb40..4d4dba55b16 100644 --- a/vql/filesystem/tempfile.go +++ b/vql/filesystem/tempfile.go @@ -13,10 +13,6 @@ type _TempfileRequest struct { Data []string `vfilter:"required,field=data"` } -type _TempfileResponse struct { - Filename string `vfilter:"required,field=filename"` -} - type TempfileFunction struct{} func (self *TempfileFunction) Call(ctx context.Context, diff --git a/vql/functions/functions.go b/vql/functions/functions.go index cd0bd8dda00..89fa0eb9da5 100644 --- a/vql/functions/functions.go +++ b/vql/functions/functions.go @@ -88,6 +88,7 @@ func (self _Now) Info(scope *vfilter.Scope, type_map *vfilter.TypeMap) *vfilter. } func init() { + vql_subsystem.RegisterFunction(&_Base64Decode{}) vql_subsystem.RegisterFunction(&_ToInt{}) vql_subsystem.RegisterFunction(&_Now{}) } diff --git a/vql/linux/users.go b/vql/linux/users.go index 5113f27d526..4f87e02d36e 100644 --- a/vql/linux/users.go +++ b/vql/linux/users.go @@ -116,13 +116,8 @@ func (self _UsersPlugin) Call( // may participate in WHERE clause and so will be // referenced after the plugin is terminated. go func() { - for { - select { - case <-ctx.Done(): - file.Close() - return - } - } + <-ctx.Done() + file.Close() }() profile := vtypes.NewProfile() diff --git a/vql/networking/uploader.go b/vql/networking/uploader.go index f43b834d79a..da268b12f9e 100644 --- a/vql/networking/uploader.go +++ b/vql/networking/uploader.go @@ -38,14 +38,14 @@ type FileBasedUploader struct { // Turn the path which may have a device name into something which can // be created as a directory. -var sanitize_re = regexp.MustCompile("[^a-zA-Z0-9_@\\(\\)\\. \\-=\\{\\}\\[\\]]") +var sanitize_re = regexp.MustCompile(`[^a-zA-Z0-9_@\(\)\. \-=\{\}\[\]]`) func sanitize_path(path string) string { // Strip any leading devices, and make sure the device name // consists of valid chars. path = regexp.MustCompile( - "\\\\\\\\[\\\\.\\\\?]\\\\([{}a-zA-Z0-9]+).*?\\\\"). - ReplaceAllString(path, "$1\\") + `\\\\[\\.\\?]\\([{}a-zA-Z0-9]+).*?\\`). + ReplaceAllString(path, `$1\`) // Split the path into components and escape any non valid // chars. diff --git a/vql/parsers/evtx.go b/vql/parsers/evtx.go index 00f54f9e3cf..7b03e5158e4 100644 --- a/vql/parsers/evtx.go +++ b/vql/parsers/evtx.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "io" - "os" "time" "github.com/0xrawsec/golang-evtx/evtx" @@ -57,7 +56,10 @@ func _WriteEvents( chunk.Offset = offsetChunk chunk.Data = make([]byte, evtx.ChunkSize) - offset, err := file.Seek(offsetChunk, os.SEEK_SET) + offset, err := file.Seek(offsetChunk, io.SeekStart) + if err != nil { + continue + } if offset != offsetChunk || err != nil { return last_event, nil } @@ -76,7 +78,7 @@ func _WriteEvents( chunk_reader.Seek( int64(chunk.Header.SizeHeader), - os.SEEK_SET) + io.SeekStart) chunk.ParseStringTable(chunk_reader) err = chunk.ParseTemplateTable(chunk_reader) if err != nil { @@ -88,7 +90,7 @@ func _WriteEvents( continue } - for _, event_offset := range chunk.EventOffsets { + for event_offset := range chunk.EventOffsets { event := chunk.ParseEvent(int64(event_offset)) item, err := event.GoEvtxMap(&chunk) if err == nil { @@ -207,9 +209,9 @@ func (self _WatchEvtxPlugin) Call( return } defer file.Close() - first_event, _ := event_counts[filename] last_event, err := _WriteEvents( - scope, file, output_chan, first_event) + scope, file, output_chan, + event_counts[filename]) if err != nil { scope.Log("Error: %v", err) return diff --git a/vql/parsers/json.go b/vql/parsers/json.go index 709afe15cc1..a8daddb4aba 100644 --- a/vql/parsers/json.go +++ b/vql/parsers/json.go @@ -83,7 +83,7 @@ func (self _MapInterfaceAssociativeProtocol) GetMembers( result := []string{} a_map, ok := a.(map[string]interface{}) if ok { - for k, _ := range a_map { + for k := range a_map { result = append(result, k) } } diff --git a/vql/parsers/splitparser.go b/vql/parsers/splitparser.go index 9552ff0ad2d..04c33eca19b 100644 --- a/vql/parsers/splitparser.go +++ b/vql/parsers/splitparser.go @@ -76,7 +76,7 @@ func processFile( continue } - for idx, _ := range items { + for idx := range items { arg.Columns = append( arg.Columns, fmt.Sprintf("Column%d", idx)) diff --git a/vql/scope.go b/vql/scope.go index 9ad82a08ecb..6d66cb4c1a5 100644 --- a/vql/scope.go +++ b/vql/scope.go @@ -17,8 +17,7 @@ func CacheGet(scope *vfilter.Scope, key string) interface{} { any_obj, _ := scope.Resolve(CACHE_VAR) cache, ok := any_obj.(*ScopeCache) if ok { - item, _ := cache.cache[key] - return item + return cache.cache[key] } return nil } diff --git a/vql/server/monitoring.go b/vql/server/monitoring.go index 47fa9ba557d..533ea8ee8f7 100644 --- a/vql/server/monitoring.go +++ b/vql/server/monitoring.go @@ -236,7 +236,6 @@ func (self WatchMonitoringPlugin) Call( return case <-time.After(time.Second): - break } } }() diff --git a/vql/windows/filesystems/os_windows.go b/vql/windows/filesystems/os_windows.go index 3e83cd3bf0a..0fec5d8fe03 100644 --- a/vql/windows/filesystems/os_windows.go +++ b/vql/windows/filesystems/os_windows.go @@ -7,7 +7,6 @@ package filesystems import ( "context" "encoding/json" - "io" "io/ioutil" "os" "path/filepath" @@ -124,26 +123,10 @@ func getPath(path string) string { return strings.TrimPrefix(path, "\\") } -type OSFileSystemAccessor struct { - fd_cache map[string]io.ReadCloser -} +type OSFileSystemAccessor struct{} func (self OSFileSystemAccessor) New(ctx context.Context) glob.FileSystemAccessor { - result := &OSFileSystemAccessor{ - fd_cache: make(map[string]io.ReadCloser), - } - - // When the context is done, close all the files. The files - // must remain open until the entire VQL query is done. - go func() { - select { - case <-ctx.Done(): - for _, v := range result.fd_cache { - v.Close() - } - } - }() - + result := &OSFileSystemAccessor{} return result }