From 1f815d1bfe8578302f7c8a5351abc8776682b734 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Wed, 16 Aug 2023 14:08:01 +0200 Subject: [PATCH 01/40] Fixes to DB --- internal/certs/certs.go | 32 +++++++++++++---------- internal/certs/users.go | 2 +- internal/db/sql.go | 4 +-- server/users.go | 56 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 17 deletions(-) diff --git a/internal/certs/certs.go b/internal/certs/certs.go index 4f7c7d0..5af5a01 100644 --- a/internal/certs/certs.go +++ b/internal/certs/certs.go @@ -63,11 +63,11 @@ var ErrCertDoesNotExist = errors.New("Certificate does not exist") // Manager is used to manage the certificate infrastructure for a given teamserver. // Has access to a given database for storage, a logger and an abstract filesystem. type Manager struct { - appName string - appDir string - log *logrus.Entry - db *gorm.DB - fs *assets.FS + appName string + appDir string + log *logrus.Entry + database *gorm.DB + fs *assets.FS } // NewManager initializes and returns a certificate manager for a given teamserver. @@ -78,11 +78,11 @@ type Manager struct { // panic and exit. func NewManager(filesystem *assets.FS, db *gorm.DB, logger *logrus.Entry, appName, appDir string) *Manager { certs := &Manager{ - appName: appName, - appDir: appDir, - log: logger, - db: db, - fs: filesystem, + appName: appName, + appDir: appDir, + log: logger, + database: db, + fs: filesystem, } certs.generateCA(userCA, "teamusers") @@ -90,6 +90,12 @@ func NewManager(filesystem *assets.FS, db *gorm.DB, logger *logrus.Entry, appNam return certs } +func (m *Manager) db() *gorm.DB { + return m.database.Session(&gorm.Session{ + FullSaveAssociations: true, + }) +} + // GetECCCertificate - Get an ECC certificate. func (c *Manager) GetECCCertificate(caType string, commonName string) ([]byte, []byte, error) { return c.GetCertificate(caType, ECCKey, commonName) @@ -109,7 +115,7 @@ func (c *Manager) GetCertificate(caType string, keyType string, commonName strin c.log.Infof("Getting certificate ca type = %s, cn = '%s'", caType, commonName) certModel := db.Certificate{} - result := c.db.Where(&db.Certificate{ + result := c.db().Where(&db.Certificate{ CAType: caType, KeyType: keyType, CommonName: commonName, @@ -134,7 +140,7 @@ func (c *Manager) RemoveCertificate(caType string, keyType string, commonName st c.log.Infof("Deleting certificate for cn = '%s'", commonName) - err := c.db.Where(&db.Certificate{ + err := c.db().Where(&db.Certificate{ CAType: caType, KeyType: keyType, CommonName: commonName, @@ -301,7 +307,7 @@ func (c *Manager) saveCertificate(caType string, keyType string, commonName stri PrivateKeyPEM: string(key), } - result := c.db.Create(&certModel) + result := c.db().Create(&certModel) return result.Error } diff --git a/internal/certs/users.go b/internal/certs/users.go index c28dac6..b0fed17 100644 --- a/internal/certs/users.go +++ b/internal/certs/users.go @@ -70,7 +70,7 @@ func (c *Manager) UserServerGenerateCertificate() ([]byte, []byte, error) { func (c *Manager) UserClientListCertificates() []*x509.Certificate { userCerts := []*db.Certificate{} - result := c.db.Where(&db.Certificate{CAType: userCA}).Find(&userCerts) + result := c.db().Where(&db.Certificate{CAType: userCA}).Find(&userCerts) if result.Error != nil { c.log.Error(result.Error) return []*x509.Certificate{} diff --git a/internal/db/sql.go b/internal/db/sql.go index ac9c0a4..713862f 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -103,9 +103,7 @@ func NewClient(dbConfig *Config, dbLogger *logrus.Entry) (*gorm.DB, error) { // SetConnMaxLifetime sets the maximum amount of time a connection may be reused. sqlDB.SetConnMaxLifetime(time.Hour) - return dbClient.Session(&gorm.Session{ - FullSaveAssociations: true, - }), nil + return dbClient, nil } // Schema returns all objects which should be registered diff --git a/server/users.go b/server/users.go index f1ec242..526dd72 100644 --- a/server/users.go +++ b/server/users.go @@ -277,3 +277,59 @@ func (ts *Server) updateLastSeen(name string) { lastSeen := time.Now().Round(1 * time.Second) ts.dbSession().Model(&db.User{}).Where("name", name).Update("LastSeen", lastSeen) } + +// func TestRootOnlyVerifyCertificate(t *testing.T) { +// certs.SetupCAs() +// +// data, err := NewOperatorConfig("zerocool", "localhost", uint16(1337)) +// if err != nil { +// t.Fatalf("failed to generate test player profile %s", err) +// } +// config := &ClientConfig{} +// err = json.Unmarshal(data, config) +// if err != nil { +// t.Fatalf("failed to parse client config %s", err) +// } +// +// _, _, err = certs.OperatorServerGetCertificate("localhost") +// if err == certs.ErrCertDoesNotExist { +// certs.OperatorServerGenerateCertificate("localhost") +// } +// +// // Test with a valid certificate +// certPEM, _, _ := certs.OperatorServerGetCertificate("localhost") +// block, _ := pem.Decode(certPEM) +// err = clienttransport.RootOnlyVerifyCertificate(config.CACertificate, [][]byte{block.Bytes}) +// if err != nil { +// t.Fatalf("root only verify certificate error: %s", err) +// } +// +// // Test with wrong CA +// wrongCert, _ := certs.GenerateECCCertificate(certs.HTTPSCA, "foobar", false, false) +// block, _ = pem.Decode(wrongCert) +// err = clienttransport.RootOnlyVerifyCertificate(config.CACertificate, [][]byte{block.Bytes}) +// if err == nil { +// t.Fatal("root only verify cert verified a certificate with invalid ca!") +// } +// +// } + +// func TestOperatorGenerateCertificate(t *testing.T) { +// GenerateCertificateAuthority(OperatorCA, "") +// cert1, key1, err := OperatorClientGenerateCertificate("test3") +// if err != nil { +// t.Errorf("Failed to store ecc certificate %v", err) +// return +// } +// +// cert2, key2, err := OperatorClientGetCertificate("test3") +// if err != nil { +// t.Errorf("Failed to get ecc certificate %v", err) +// return +// } +// +// if !bytes.Equal(cert1, cert2) || !bytes.Equal(key1, key2) { +// t.Errorf("Stored ecc cert/key does match generated cert/key: %v != %v", cert1, cert2) +// return +// } +// } From 80e332665d96a5b0217764e4c64cb0fd767eb294 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 05:25:44 +0200 Subject: [PATCH 02/40] Add WithTeamDirectory() option to client/servers --- client/directories.go | 2 +- client/options.go | 40 ++++++++++++++++++++++++++++++++++------ server/options.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/client/directories.go b/client/directories.go index 448a2c0..96430bf 100644 --- a/client/directories.go +++ b/client/directories.go @@ -57,7 +57,7 @@ func (tc *Client) HomeDir() string { // creating the directory if needed, or logging an error event if failing to create it. // This directory is used to store teamclient logs and remote server configs. func (tc *Client) TeamDir() string { - dir := filepath.Join(tc.HomeDir(), assets.DirClient) + dir := filepath.Join(tc.HomeDir(), tc.opts.teamDir) err := tc.fs.MkdirAll(dir, log.DirPerm) if err != nil { diff --git a/client/options.go b/client/options.go index 4b0b81d..864ca35 100644 --- a/client/options.go +++ b/client/options.go @@ -24,9 +24,12 @@ import ( "os" "strings" + "github.com/reeflective/team/internal/assets" "github.com/sirupsen/logrus" ) +const noTeamdir = "no team subdirectory" + // Options are client options. // You can set or modify the behavior of a teamclient at various // steps with these options, which are a variadic parameter of @@ -39,6 +42,7 @@ type Options func(opts *opts) type opts struct { homeDir string + teamDir string noLogs bool logFile string inMemory bool @@ -77,6 +81,13 @@ func (tc *Client) apply(options ...Options) { tc.dialer = tc.opts.dialer } + // Team directory. + if tc.opts.teamDir == noTeamdir { + tc.opts.teamDir = "" + } else if tc.opts.teamDir == "" { + tc.opts.teamDir = assets.DirClient + } + if tc.opts.stdout != nil { tc.stdoutLogger.Out = tc.opts.stdout } @@ -91,7 +102,7 @@ func (tc *Client) apply(options ...Options) { // This might be useful for testing, or if you happen to embed a teamclient in a program // without the intent of using it now, etc. // -// This option can only be used once, and should be passed to server.New(). +// This option can only be used once, and should be passed client.New(). func WithInMemory() Options { return func(opts *opts) { opts.noLogs = true @@ -110,13 +121,30 @@ func WithConfig(config *Config) Options { // WithHomeDirectory sets the default path (~/.app/) of the application directory. // This path can still be overridden at the user-level with the env var APP_ROOT_DIR. // -// This option can only be used once, and must be passed to server.New(). +// This option can only be used once, and must be passed client.New(). func WithHomeDirectory(path string) Options { return func(opts *opts) { opts.homeDir = path } } +// WithTeamDirectory sets the name (not a path) of the teamclient-specific subdirectory. +// For example, passing "my_team_dir" will make the teamclient use ~/.app/my_team_dir/ +// instead of ~/.app/teamclient/. +// If this function is called with an empty string, the teamclient will not use any +// subdirectory for its own outputs, thus using ~/.app as its teamclient directory. +// +// This option can only be used once, and should be passed client.New(). +func WithTeamDirectory(name string) Options { + return func(opts *opts) { + if name == "" { + name = noTeamdir + } + + opts.teamDir = name + } +} + // // *** Logging options *** // @@ -124,7 +152,7 @@ func WithHomeDirectory(path string) Options { // WithNoLogs deactivates all logging normally done by the teamclient // if noLogs is set to true, or keeps/reestablishes them if false. // -// This option can only be used once, and should be passed to server.New(). +// This option can only be used once, and should be passed client.New(). func WithNoLogs(noLogs bool) Options { return func(opts *opts) { opts.noLogs = noLogs @@ -134,7 +162,7 @@ func WithNoLogs(noLogs bool) Options { // WithLogFile sets the path to the file where teamclient logging should be done. // If not specified, the client log file is ~/.app/teamclient/logs/app.teamclient.log. // -// This option can only be used once, and should be passed to server.New(). +// This option can only be used once, and should be passed client.New(). func WithLogFile(filePath string) Options { return func(opts *opts) { opts.logFile = filePath @@ -143,7 +171,7 @@ func WithLogFile(filePath string) Options { // WithLogger sets the teamclient to use a specific logger for logging. // -// This option can only be used once, and should be passed to server.New(). +// This option can only be used once, and should be passed client.New(). func WithLogger(logger *logrus.Logger) Options { return func(opts *opts) { opts.logger = logger @@ -177,7 +205,7 @@ func WithDialer(dialer Dialer) Options { // If this is the case, this option will ensure that any cobra client command // runners produced by this library will not disconnect after each execution. // -// This option can only be used once, and should be passed to server.New(). +// This option can only be used once, and should be passed client.New(). func WithNoDisconnect() Options { return func(opts *opts) { opts.console = true diff --git a/server/options.go b/server/options.go index 97a26e7..fe0b148 100644 --- a/server/options.go +++ b/server/options.go @@ -23,11 +23,14 @@ import ( "os" "strings" + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/db" "github.com/sirupsen/logrus" "gorm.io/gorm" ) +const noTeamdir = "no team subdirectory" + // Options are server options. // With these you can set/reset or modify the behavior of a teamserver // at various stages of its lifetime, or when performing some specific @@ -40,6 +43,7 @@ type Options func(opts *opts) type opts struct { homeDir string + teamDir string logFile string local bool noLogs bool @@ -80,6 +84,13 @@ func (ts *Server) apply(options ...Options) { ts.homeDir = ts.opts.homeDir } + // Team directory. + if ts.opts.teamDir == noTeamdir { + ts.opts.teamDir = "" + } else if ts.opts.teamDir == "" { + ts.opts.teamDir = assets.DirServer + } + // User-defined database. if ts.opts.db != nil { ts.db = ts.opts.db @@ -161,6 +172,23 @@ func WithHomeDirectory(path string) Options { } } +// WithTeamDirectory sets the name (not a path) of the teamserver-specific subdirectory. +// For example, passing "my_server_dir" will make the teamserver use ~/.app/my_server_dir/ +// instead of ~/.app/teamserver/. +// If this function is called with an empty string, the teamserver will not use any +// subdirectory for its own outputs, thus using ~/.app as its teamserver directory. +// +// This option can only be used once, and must be passed to server.New(). +func WithTeamDirectory(name string) Options { + return func(opts *opts) { + if name == "" { + name = noTeamdir + } + + opts.teamDir = name + } +} + // // *** Logging options *** // From 1a31b3ece35b6273959efe7f246a42dcd1a65198 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 07:59:17 +0200 Subject: [PATCH 03/40] Fix version printing and add method to team.Client interface. --- client/client.go | 40 +++++++++++++++++++++++++++++++++++--- client/commands/version.go | 34 +++++++++++++++++++------------- server/core.go | 11 ++++++++--- server/directories.go | 33 +------------------------------ teamclient.go | 6 +++++- 5 files changed, 71 insertions(+), 53 deletions(-) diff --git a/client/client.go b/client/client.go index 7594050..9c9e776 100644 --- a/client/client.go +++ b/client/client.go @@ -21,10 +21,12 @@ package client import ( "os/user" "path/filepath" + "runtime" "sync" "github.com/reeflective/team" "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/version" "github.com/sirupsen/logrus" ) @@ -225,16 +227,48 @@ func (tc *Client) Users() (users []team.User, err error) { return res, nil } -// ServerVersion returns the version information of the server to which +// VersionClient returns the version information of the client, and thus +// does not require the teamclient to be connected to a teamserver. +// This function satisfies the VersionClient() function of the team.Client interface, +// which means that library users are free to reimplement it however they wish. +func (tc *Client) VersionClient() (ver team.Version, err error) { + if tc.client != nil { + return tc.client.VersionClient() + } + + semVer := version.Semantic() + compiled, _ := version.Compiled() + + var major, minor, patch int32 + + if len(semVer) == 3 { + major = int32(semVer[0]) + minor = int32(semVer[1]) + patch = int32(semVer[2]) + } + + return team.Version{ + Major: major, + Minor: minor, + Patch: patch, + Commit: version.GitCommit(), + Dirty: version.GitDirty(), + CompiledAt: compiled.Unix(), + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }, nil +} + +// VersionServer returns the version information of the server to which // the client is connected. // If the teamclient has no backend, it returns an ErrNoTeamclient error. // If the backend returns an error, the latter is returned as is. -func (tc *Client) ServerVersion() (ver team.Version, err error) { +func (tc *Client) VersionServer() (ver team.Version, err error) { if tc.client == nil { return ver, ErrNoTeamclient } - version, err := tc.client.Version() + version, err := tc.client.VersionServer() if err != nil { return } diff --git a/client/commands/version.go b/client/commands/version.go index f3dfa59..975c0d9 100644 --- a/client/commands/version.go +++ b/client/commands/version.go @@ -20,10 +20,10 @@ package commands import ( "fmt" + "time" "github.com/reeflective/team/client" "github.com/reeflective/team/internal/command" - "github.com/reeflective/team/internal/version" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -42,28 +42,34 @@ func versionCmd(cli *client.Client) func(cmd *cobra.Command, args []string) erro } // Server - serverVer, err := cli.ServerVersion() + serverVer, err := cli.VersionServer() if err != nil { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Server error: %s\n", err) } - dirty := "" - if serverVer.Dirty { - dirty = fmt.Sprintf(" - %sDirty%s", command.Bold, command.Normal) - } + serverVerInfo := fmt.Sprintf("Server v%d.%d.%d - %s - %s/%s\n", + serverVer.Major, serverVer.Minor, serverVer.Patch, serverVer.Commit, + serverVer.OS, serverVer.Arch) + serverCompiledAt := time.Unix(serverVer.CompiledAt, 0) - serverSemVer := fmt.Sprintf("%d.%d.%d", serverVer.Major, serverVer.Minor, serverVer.Patch) - fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Server v%s - %s%s\n", serverSemVer, serverVer.Commit, dirty) + fmt.Fprint(cmd.OutOrStdout(), command.Info+serverVerInfo) + fmt.Fprintf(cmd.OutOrStdout(), " Compiled at %s\n", serverCompiledAt) + fmt.Fprintln(cmd.OutOrStdout()) // Client - cdirty := "" - if version.GitDirty() { - cdirty = fmt.Sprintf(" - %sDirty%s", command.Bold, command.Normal) + clientVer, err := cli.VersionClient() + if err != nil { + fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Client error: %s\n", err) + return nil } - cliVer := version.Semantic() - cliSemVer := fmt.Sprintf("%d.%d.%d", cliVer[0], cliVer[1], cliVer[2]) - fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Client v%s - %s%s\n", cliSemVer, version.GitCommit(), cdirty) + clientVerInfo := fmt.Sprintf("Client v%d.%d.%d - %s - %s/%s\n", + clientVer.Major, clientVer.Minor, clientVer.Patch, clientVer.Commit, + clientVer.OS, clientVer.Arch) + clientCompiledAt := time.Unix(clientVer.CompiledAt, 0) + + fmt.Fprint(cmd.OutOrStdout(), command.Info+clientVerInfo) + fmt.Fprintf(cmd.OutOrStdout(), " Compiled at %s\n", clientCompiledAt) return nil } diff --git a/server/core.go b/server/core.go index 458c078..6f562c4 100644 --- a/server/core.go +++ b/server/core.go @@ -154,15 +154,20 @@ func (ts *Server) Name() string { // of the application using this teamserver. // See the server.Listener and client.Dialer types documentation for more. func (ts *Server) Self(opts ...client.Options) *client.Client { - // opts = append(opts, client.WithLocalDialer()) - teamclient, _ := client.New(ts.Name(), ts, opts...) return teamclient } +// Version implements team.Client.VersionClient() interface +// method, so that the teamserver can be a teamclient of itself. +// This simply returns the server.VersionServer() output. +func (ts *Server) VersionClient() (team.Version, error) { + return ts.VersionServer() +} + // Version returns the teamserver binary version information. -func (ts *Server) Version() (team.Version, error) { +func (ts *Server) VersionServer() (team.Version, error) { semVer := version.Semantic() compiled, _ := version.Compiled() diff --git a/server/directories.go b/server/directories.go index 188aa74..4c96c2a 100644 --- a/server/directories.go +++ b/server/directories.go @@ -19,8 +19,6 @@ package server */ import ( - "fmt" - "os" "os/user" "path" "path/filepath" @@ -60,7 +58,7 @@ func (ts *Server) HomeDir() string { // creating the directory if needed, or logging an error event if failing to create it. // This directory is used to store teamserver certificates, database, logs, and configs. func (ts *Server) TeamDir() string { - dir := path.Join(ts.HomeDir(), assets.DirServer) + dir := path.Join(ts.HomeDir(), ts.opts.teamDir) err := ts.fs.MkdirAll(dir, log.DirPerm) if err != nil { @@ -95,32 +93,3 @@ func (ts *Server) CertificatesDir() string { return certDir } - -// When creating a new server, don't write anything to anywhere yet, -// but ensure that at least all directories to which we are supposed -// to write do indeed exist, and make them anyway. -// If any error happens it will returned right away and the creator -// of the teamserver will know right away that it can't work correctly. -func (ts *Server) checkWritableFiles() error { - if ts.opts.inMemory { - return nil - } - - // Check home application directory. - // If it does not exist but we don't have write permission - // on /user/home, we return an error as we can't work. - appDirWrite, err := log.IsWritable(ts.TeamDir()) - - switch { - case os.IsNotExist(err): - if homeWritable, err := log.IsWritable(os.Getenv("HOME")); !homeWritable { - return fmt.Errorf("Cannot create %w", err) - } - case err != nil: - return fmt.Errorf("Cannot write to %w", err) - case !appDirWrite: - return ErrDirectoryUnwritable - } - - return nil -} diff --git a/teamclient.go b/teamclient.go index 9a58747..07fdefd 100644 --- a/teamclient.go +++ b/teamclient.go @@ -28,8 +28,12 @@ import "time" // is to be provided by the teamclients and teamservers alike. // - To harmonize the use of team/client and team/server core drivers. type Client interface { + // Users returns the list of teamserver users and their status. Users() ([]User, error) - Version() (Version, error) + // VersionClient returns the compilation/version information for the client. + VersionClient() (Version, error) + // VersionServer returns the compilation/version information from a connected teamserver. + VersionServer() (Version, error) } // User represents a teamserver user. From 54017bc822f7b00b94b99f16e4bc2d5d812905db Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 08:27:11 +0200 Subject: [PATCH 04/40] Move transports to example directory --- .golangci.yml | 13 +++++++++---- example/teamclient/main.go | 5 +++-- example/teamserver/main.go | 5 +++-- .../transports}/grpc/client/client.go | 7 ++++--- .../transports}/grpc/client/middleware.go | 2 +- .../transports}/grpc/common/log.go | 0 .../transports}/grpc/proto/buf.gen.yaml | 0 .../transports}/grpc/proto/buf.work.yaml | 0 .../transports}/grpc/proto/buf.yaml | 0 .../transports}/grpc/proto/client.pb.go | 0 .../transports}/grpc/proto/client.proto | 0 .../transports}/grpc/proto/service.pb.go | 0 .../transports}/grpc/proto/service.proto | 0 .../transports}/grpc/proto/service_grpc.pb.go | 0 .../transports}/grpc/server/middleware.go | 14 +++++++------- .../transports}/grpc/server/rpc.go | 4 ++-- .../transports}/grpc/server/server.go | 11 +++++++---- go.mod | 2 +- 18 files changed, 37 insertions(+), 26 deletions(-) rename {transports => example/transports}/grpc/client/client.go (98%) rename {transports => example/transports}/grpc/client/middleware.go (98%) rename {transports => example/transports}/grpc/common/log.go (100%) rename {transports => example/transports}/grpc/proto/buf.gen.yaml (100%) rename {transports => example/transports}/grpc/proto/buf.work.yaml (100%) rename {transports => example/transports}/grpc/proto/buf.yaml (100%) rename {transports => example/transports}/grpc/proto/client.pb.go (100%) rename {transports => example/transports}/grpc/proto/client.proto (100%) rename {transports => example/transports}/grpc/proto/service.pb.go (100%) rename {transports => example/transports}/grpc/proto/service.proto (100%) rename {transports => example/transports}/grpc/proto/service_grpc.pb.go (100%) rename {transports => example/transports}/grpc/server/middleware.go (95%) rename {transports => example/transports}/grpc/server/rpc.go (95%) rename {transports => example/transports}/grpc/server/server.go (95%) diff --git a/.golangci.yml b/.golangci.yml index 5389185..10065e6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -183,10 +183,10 @@ linters: - godot # checks if comments end in a period (style,cmt) - godox # tool for detection of FIXME, TODO and other comments (style,cmt) - goerr113 # checks the errors handling expressions (style,err) - - gofmt # formats and checks for code simplification (fmt) - - gofumpt # checks whether code was gofumpt-ed (fmt) + # - gofmt # formats and checks for code simplification (fmt) + # - gofumpt # checks whether code was gofumpt-ed (fmt) - goheader # checks if file header matches to pattern (style) - # - goimports # fixes imports, formats code same as gofmt (fmt,import) + - goimports # fixes imports, formats code same as gofmt (fmt,import) # - golint # Deprecated - gomnd # analyzer to detect magic numbers (style) - gomoddirectives # manage replace/retract/excludes directives in go.mod (style,mod) @@ -261,7 +261,7 @@ linters: - forbidigo # Forbids identifiers (style) - gochecknoglobals # checks that no global variables exist (style) - gochecknoinits # checks that no init functions are present (style) - - goimports # fixes imports, formats code same as gofmt (fmt,import) + #- goimports # fixes imports, formats code same as gofmt (fmt,import) - lll # Report long lines (style) - promlinter # checks Prometheus metrics naming via promlint - rowserrcheck # checks if Err of rows is checked successfully (bugs,sql) @@ -280,6 +280,8 @@ linters: - musttag - wrapcheck # checks errors returned from external packages are wrapped (style,err) - tagliatelle # checks struct tags (style) + - gofmt # formats and checks for code simplification (fmt) + - gofumpt # checks whether code was gofumpt-ed (fmt) # Run only fast linters from enabled linters set (first run won't be fast) # Default: false @@ -337,6 +339,9 @@ linters-settings: paralleltest: ignore-missing: true + goimports: + local-prefixes: github.com/reeflective/team + # # ----------------------- Other exclusions & Issues management -------------------------- # # diff --git a/example/teamclient/main.go b/example/teamclient/main.go index 275ac7e..ded0559 100644 --- a/example/teamclient/main.go +++ b/example/teamclient/main.go @@ -3,10 +3,11 @@ package main import ( "log" + "github.com/rsteube/carapace" + "github.com/reeflective/team/client" "github.com/reeflective/team/client/commands" - grpc "github.com/reeflective/team/transports/grpc/client" - "github.com/rsteube/carapace" + grpc "github.com/reeflective/team/example/transports/grpc/client" ) // main shows how to use a remote teamclient with a gRPC backend (transport & RPC). diff --git a/example/teamserver/main.go b/example/teamserver/main.go index 46b4300..61803af 100644 --- a/example/teamserver/main.go +++ b/example/teamserver/main.go @@ -3,11 +3,12 @@ package main import ( "log" + "github.com/rsteube/carapace" + "github.com/reeflective/team/client" + grpc "github.com/reeflective/team/example/transports/grpc/server" "github.com/reeflective/team/server" "github.com/reeflective/team/server/commands" - grpc "github.com/reeflective/team/transports/grpc/server" - "github.com/rsteube/carapace" ) // main shows how to use a teamserver and teamclient with gRPC backends (transport & RPC). diff --git a/transports/grpc/client/client.go b/example/transports/grpc/client/client.go similarity index 98% rename from transports/grpc/client/client.go rename to example/transports/grpc/client/client.go index c1d7005..ac66e61 100644 --- a/transports/grpc/client/client.go +++ b/example/transports/grpc/client/client.go @@ -24,11 +24,12 @@ import ( "fmt" "time" - "github.com/reeflective/team" - "github.com/reeflective/team/client" - "github.com/reeflective/team/transports/grpc/proto" "google.golang.org/grpc" "google.golang.org/grpc/status" + + "github.com/reeflective/team" + "github.com/reeflective/team/client" + "github.com/reeflective/team/example/transports/grpc/proto" ) const ( diff --git a/transports/grpc/client/middleware.go b/example/transports/grpc/client/middleware.go similarity index 98% rename from transports/grpc/client/middleware.go rename to example/transports/grpc/client/middleware.go index e0f0f37..45a4a22 100644 --- a/transports/grpc/client/middleware.go +++ b/example/transports/grpc/client/middleware.go @@ -24,7 +24,7 @@ import ( grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" "github.com/reeflective/team/client" - "github.com/reeflective/team/transports/grpc/common" + "github.com/reeflective/team/example/transports/grpc/common" "google.golang.org/grpc" "google.golang.org/grpc/credentials" ) diff --git a/transports/grpc/common/log.go b/example/transports/grpc/common/log.go similarity index 100% rename from transports/grpc/common/log.go rename to example/transports/grpc/common/log.go diff --git a/transports/grpc/proto/buf.gen.yaml b/example/transports/grpc/proto/buf.gen.yaml similarity index 100% rename from transports/grpc/proto/buf.gen.yaml rename to example/transports/grpc/proto/buf.gen.yaml diff --git a/transports/grpc/proto/buf.work.yaml b/example/transports/grpc/proto/buf.work.yaml similarity index 100% rename from transports/grpc/proto/buf.work.yaml rename to example/transports/grpc/proto/buf.work.yaml diff --git a/transports/grpc/proto/buf.yaml b/example/transports/grpc/proto/buf.yaml similarity index 100% rename from transports/grpc/proto/buf.yaml rename to example/transports/grpc/proto/buf.yaml diff --git a/transports/grpc/proto/client.pb.go b/example/transports/grpc/proto/client.pb.go similarity index 100% rename from transports/grpc/proto/client.pb.go rename to example/transports/grpc/proto/client.pb.go diff --git a/transports/grpc/proto/client.proto b/example/transports/grpc/proto/client.proto similarity index 100% rename from transports/grpc/proto/client.proto rename to example/transports/grpc/proto/client.proto diff --git a/transports/grpc/proto/service.pb.go b/example/transports/grpc/proto/service.pb.go similarity index 100% rename from transports/grpc/proto/service.pb.go rename to example/transports/grpc/proto/service.pb.go diff --git a/transports/grpc/proto/service.proto b/example/transports/grpc/proto/service.proto similarity index 100% rename from transports/grpc/proto/service.proto rename to example/transports/grpc/proto/service.proto diff --git a/transports/grpc/proto/service_grpc.pb.go b/example/transports/grpc/proto/service_grpc.pb.go similarity index 100% rename from transports/grpc/proto/service_grpc.pb.go rename to example/transports/grpc/proto/service_grpc.pb.go diff --git a/transports/grpc/server/middleware.go b/example/transports/grpc/server/middleware.go similarity index 95% rename from transports/grpc/server/middleware.go rename to example/transports/grpc/server/middleware.go index 9414ee1..043fd44 100644 --- a/transports/grpc/server/middleware.go +++ b/example/transports/grpc/server/middleware.go @@ -22,17 +22,17 @@ import ( "context" "encoding/json" - grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_tags "github.com/grpc-ecosystem/go-grpc-middleware/tags" - "github.com/reeflective/team/server" - "github.com/reeflective/team/transports/grpc/common" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" + + "github.com/reeflective/team/example/transports/grpc/common" + "github.com/reeflective/team/server" ) // BufferingOptions returns a list of server options with max send/receive @@ -96,8 +96,8 @@ func LogMiddlewareOptions(s *server.Server) ([]grpc.ServerOption, error) { ) return []grpc.ServerOption{ - grpc_middleware.WithUnaryServerChain(requestOpts...), - grpc_middleware.WithStreamServerChain(streamOpts...), + grpc.ChainUnaryInterceptor(requestOpts...), + grpc.ChainStreamInterceptor(streamOpts...), }, nil } @@ -146,8 +146,8 @@ func (ts *Teamserver) initAuthMiddleware() ([]grpc.ServerOption, error) { // Return middleware for all requests and stream interactions in gRPC. return []grpc.ServerOption{ - grpc_middleware.WithUnaryServerChain(requestOpts...), - grpc_middleware.WithStreamServerChain(streamOpts...), + grpc.ChainUnaryInterceptor(requestOpts...), + grpc.ChainStreamInterceptor(streamOpts...), }, nil } diff --git a/transports/grpc/server/rpc.go b/example/transports/grpc/server/rpc.go similarity index 95% rename from transports/grpc/server/rpc.go rename to example/transports/grpc/server/rpc.go index 2f206cd..2cbd6e5 100644 --- a/transports/grpc/server/rpc.go +++ b/example/transports/grpc/server/rpc.go @@ -21,8 +21,8 @@ package server import ( "context" + "github.com/reeflective/team/example/transports/grpc/proto" "github.com/reeflective/team/server" - "github.com/reeflective/team/transports/grpc/proto" ) // rpcServer is the gRPC server implementation. @@ -41,7 +41,7 @@ func newServer(server *server.Server) *rpcServer { // GetVersion returns the teamserver version. func (ts *rpcServer) GetVersion(context.Context, *proto.Empty) (*proto.Version, error) { - ver, err := ts.server.Version() + ver, err := ts.server.VersionServer() return &proto.Version{ Major: ver.Major, diff --git a/transports/grpc/server/server.go b/example/transports/grpc/server/server.go similarity index 95% rename from transports/grpc/server/server.go rename to example/transports/grpc/server/server.go index e86a01b..421b6a1 100644 --- a/transports/grpc/server/server.go +++ b/example/transports/grpc/server/server.go @@ -24,11 +24,13 @@ import ( "runtime/debug" "sync" - teamserver "github.com/reeflective/team/server" - clientConn "github.com/reeflective/team/transports/grpc/client" - "github.com/reeflective/team/transports/grpc/proto" "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/test/bufconn" + + clientConn "github.com/reeflective/team/example/transports/grpc/client" + "github.com/reeflective/team/example/transports/grpc/proto" + teamserver "github.com/reeflective/team/server" ) const ( @@ -78,6 +80,7 @@ func NewListener(opts ...grpc.ServerOption) *Teamserver { // It returns a teamclient meant to be ran in memory, with TLS credentials disabled. func NewClientFrom(server *Teamserver, opts ...grpc.DialOption) *clientConn.Teamclient { conn := bufconn.Listen(bufSize) + insecureCreds := insecure.NewCredentials() ctxDialer := grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return conn.Dial() @@ -85,7 +88,7 @@ func NewClientFrom(server *Teamserver, opts ...grpc.DialOption) *clientConn.Team opts = append(opts, []grpc.DialOption{ ctxDialer, - grpc.WithInsecure(), + grpc.WithTransportCredentials(insecureCreds), }...) // The server will use this conn as a listener. diff --git a/go.mod b/go.mod index 143a773..f1cd7bd 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/jedib0t/go-pretty/v6 v6.4.6 github.com/mattn/go-sqlite3 v1.14.17 github.com/ncruces/go-sqlite3 v0.8.1 + github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e github.com/rsteube/carapace v0.37.3 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.7.0 @@ -41,7 +42,6 @@ require ( github.com/mattn/go-runewidth v0.0.13 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/ncruces/julianday v0.1.5 // indirect - github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect From 2ea0e4a18dfbb339053233dc796700836db49b1c Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 08:35:14 +0200 Subject: [PATCH 05/40] Print daemon listening status --- .golangci.yml | 4 ++-- server/commands/teamserver.go | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 10065e6..b27a7fd 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -186,7 +186,7 @@ linters: # - gofmt # formats and checks for code simplification (fmt) # - gofumpt # checks whether code was gofumpt-ed (fmt) - goheader # checks if file header matches to pattern (style) - - goimports # fixes imports, formats code same as gofmt (fmt,import) + #- goimports # fixes imports, formats code same as gofmt (fmt,import) # - golint # Deprecated - gomnd # analyzer to detect magic numbers (style) - gomoddirectives # manage replace/retract/excludes directives in go.mod (style,mod) @@ -261,7 +261,7 @@ linters: - forbidigo # Forbids identifiers (style) - gochecknoglobals # checks that no global variables exist (style) - gochecknoinits # checks that no init functions are present (style) - #- goimports # fixes imports, formats code same as gofmt (fmt,import) + - goimports # fixes imports, formats code same as gofmt (fmt,import) - lll # Report long lines (style) - promlinter # checks Prometheus metrics naming via promlint - rowserrcheck # checks if Err of rows is checked successfully (bugs,sql) diff --git a/server/commands/teamserver.go b/server/commands/teamserver.go index f5fe3f2..0221ee3 100644 --- a/server/commands/teamserver.go +++ b/server/commands/teamserver.go @@ -62,6 +62,17 @@ func daemoncmd(serv *server.Server) func(cmd *cobra.Command, args []string) erro } }() + // cli args take precedence over config (this is here for status printing purposes) + if lhost == "" { + lhost = serv.GetConfig().DaemonMode.Host + } + + if lport == 0 { + lport = uint16(serv.GetConfig().DaemonMode.Port) + } + + fmt.Fprintf(cmd.OutOrStdout(), "Starting %s teamserver daemon on %s:%d ...", serv.Name(), lhost, lport) + // Blocking call, your program will only exit/resume on Ctrl-C/SIGTERM return serv.ServeDaemon(lhost, lport) } From d8c7c9c9b5717775bfe0f24e5a893916b91367ca Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 09:02:35 +0200 Subject: [PATCH 06/40] Fix log level not printed in status --- server/commands/teamserver.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/commands/teamserver.go b/server/commands/teamserver.go index 0221ee3..4a3fff0 100644 --- a/server/commands/teamserver.go +++ b/server/commands/teamserver.go @@ -225,6 +225,7 @@ func statusCmd(serv *server.Server) func(cmd *cobra.Command, args []string) { cfg := serv.GetConfig() dbCfg := serv.DatabaseConfig() + database := fmt.Sprintf("%s - %s [%s:%d] ", dbCfg.Dialect, dbCfg.Database, dbCfg.Host, dbCfg.Port) // General options, in-memory, default port, config path, database, etc @@ -241,7 +242,7 @@ func statusCmd(serv *server.Server) func(cmd *cobra.Command, args []string) { fmt.Fprintln(cmd.OutOrStdout(), formatSection("Logging")) fmt.Fprint(cmd.OutOrStdout(), displayGroup([]string{ - "Level", fakeLog.Level.String(), + "Level", fakeLog.Logger.Level.String(), "Root", log.FileName(filepath.Join(serv.LogsDir(), serv.Name()), true), "Audit", filepath.Join(serv.LogsDir(), "audit.json"), })) From 5af72d73b1448e2030a79f8bfbe31bdeebfb4ce0 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 11:50:58 +0200 Subject: [PATCH 07/40] Add some stuff to README --- README.md | 83 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index d9e926c..4246809 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,4 @@ - - - - - - - - - - - - - - - - - - - - -

Team

@@ -66,23 +45,78 @@ ----- - ## Summary +The client-server paradigm is an ubiquitous concept in computer science. Equally large and common is the problem +of building software that _collaborates_ easily with other peer programs. Although writing collaborative software +seems to be the daily task of many engineers around the world, succeedingly and easily doing so in big programs +as well as in smaller ones is not more easily done than said. Difficulty still increases -and keeping in mind that +humans use software and not the inverse- when programs must enhance the capacity of humans to collaborate while +not restricting the number of ways they can do so, for small tasks as well as for complex ones. + +The `reeflective/team` library provides a small toolset for arbitrary programs (and especially those controlled in +more or less interactive ways) to collaborate together by acting as clients and servers of each others, as part +of a team. Teams being made of players (humans _and_ their tools), the library focuses on offering "human teaming" +infrastructure and tools: that is, treating software tools that are either _teamclients_ or _teamservers_ of others. + +The project originates from the refactoring of a security-oriented tool that used this approach to clearly segregate +client and server binary code (the former's not needing most of the latter's). Besides, the large exposure of the +said-tool to the CLI prompted the author to rethink how the "collaborative" problem could be approached and explored +from different viewpoints: distinguishing between the tools' developers, and their users. After having to reuse this +core code for other projects, the idea appeared to extract the relevant parts and to restructure and repackage them +behind coherent interfaces (API and CLI). + +The result of this refactoring consists in 2 Go packages (`client` and `server`) for programs needing to act as: +- A `Teamclient`: a program, or one of its components, that needs to rely on a "remote" program peer to serve some + functionality that is available to a team of users' tools. The program acting as a _teamclient_ may do so for + things as simple as sending a message to the team, or as complicated as a compiler backend with which multiple + client programs can send data to process and build. +- A `Teamserver`: The remote, server-side counterpart of the software teamclient. Again, the teamserver can be + doing anything, from simply notifying users' teamclient connections to all the team all the way to handling + very complex and resource-hungry tasks that can only be ran on a server host. + +"team tool" + ----- +## Purposes, Constraints and Features + +The library rests on several principles, constraints and ideas to fulfill its intended purpose: +- The library's sole aim is to **make most programs able to collaborate together** under the paradigm of team clients + and team servers, and to do so while ensuring performance, coherence, ease of use and security of all processes + and workflows involved. This, under the _separate viewpoints_ of tool development, enhancement and usage. +- Ensure a **working-by-default toolset**, assuming that the time spent on any tool's configuration is inversely + proportional to its usage. Emphasis on this aspect should apply equally well to team tools' users and developers. +- **Accomodate for the needs of developers to use more specific components**, at times or at points, while not hampering + on the working-by-default aspects of the team client/server toolset. Examples include replacing parts or all of the + transport, RPC, loggers, database and filesystem backends. +- To that effect, the library **offer different interfaces to its functionality**: an API (Go code) aiming to provide + developers a working-by-default, simple but powerful way to instruct their software how to collaborate with peers. -## CLI examples (users) ----- +## CLI examples (users) +----- ## API examples (developers) ----- - ## Documentation ----- +## Differences with Hashicorp Go plugin system + +At first glance, different and not much related to our current topic is the equally large problem of dynamic code +loading and execution for arbitrary programs. In the spectrum of major programming languages, various approaches +have been taken to tackle the dynamic linking, loading and execution problem, with interpreted languages offering +the most common solutioning approach to this. +The Go language (and many other compiled languages that do not encourage dynamic linking for that matter) has to deal with +the problem through other means, the first of which simply being the adoption of different architectural designs in the +first place (eg. "microservices"). Another path has been the "plugin system" for emulating the dynamic workflows of interpreted +languages, of which the most widely used attempt being the [Hashicorp plugin system](https://github.com/hashicorp/go-plugin), which entirely rests on an (g)RPC backend. + + +----- ## Status The Command-Line and Application-Programming Interfaces of this library are unlikely to change @@ -99,7 +133,6 @@ to 9 minor releases (`0.1.0`, `0.2.0`, `0.3.0`, etc...), ending up in `v1.0.0`. - New features and/or PRs are welcome if they are likely to be useful to most users. ----- - ## Possible enhancements The list below is not an indication on the roadmap of this repository, but should be viewed as From 8c15e1556bfe30a5e81f4a16a709db37e74b9bf0 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 12:24:25 +0200 Subject: [PATCH 08/40] Add more to README --- README.md | 126 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 77 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 4246809..daa23df 100644 --- a/README.md +++ b/README.md @@ -47,51 +47,77 @@ ----- ## Summary -The client-server paradigm is an ubiquitous concept in computer science. Equally large and common is the problem -of building software that _collaborates_ easily with other peer programs. Although writing collaborative software -seems to be the daily task of many engineers around the world, succeedingly and easily doing so in big programs -as well as in smaller ones is not more easily done than said. Difficulty still increases -and keeping in mind that -humans use software and not the inverse- when programs must enhance the capacity of humans to collaborate while -not restricting the number of ways they can do so, for small tasks as well as for complex ones. - -The `reeflective/team` library provides a small toolset for arbitrary programs (and especially those controlled in -more or less interactive ways) to collaborate together by acting as clients and servers of each others, as part -of a team. Teams being made of players (humans _and_ their tools), the library focuses on offering "human teaming" -infrastructure and tools: that is, treating software tools that are either _teamclients_ or _teamservers_ of others. - -The project originates from the refactoring of a security-oriented tool that used this approach to clearly segregate -client and server binary code (the former's not needing most of the latter's). Besides, the large exposure of the -said-tool to the CLI prompted the author to rethink how the "collaborative" problem could be approached and explored -from different viewpoints: distinguishing between the tools' developers, and their users. After having to reuse this -core code for other projects, the idea appeared to extract the relevant parts and to restructure and repackage them -behind coherent interfaces (API and CLI). - -The result of this refactoring consists in 2 Go packages (`client` and `server`) for programs needing to act as: -- A `Teamclient`: a program, or one of its components, that needs to rely on a "remote" program peer to serve some - functionality that is available to a team of users' tools. The program acting as a _teamclient_ may do so for - things as simple as sending a message to the team, or as complicated as a compiler backend with which multiple - client programs can send data to process and build. -- A `Teamserver`: The remote, server-side counterpart of the software teamclient. Again, the teamserver can be - doing anything, from simply notifying users' teamclient connections to all the team all the way to handling - very complex and resource-hungry tasks that can only be ran on a server host. - -"team tool" +The client-server paradigm is an ubiquitous concept in computer science. Equally large and common is +the problem of building software that _collaborates_ easily with other peer programs. Although +writing collaborative software seems to be the daily task of many engineers around the world, +succeedingly and easily doing so in big programs as well as in smaller ones is not more easily done +than said. Difficulty still increases -and keeping in mind that humans use software and not the +inverse- when programs must enhance the capacity of humans to collaborate while not restricting the +number of ways they can do so, for small tasks as well as for complex ones. + +The `reeflective/team` library provides a small toolset for arbitrary programs (and especially those +controlled in more or less interactive ways) to collaborate together by acting as clients and +servers of each others, as part of a team. Teams being made of players (humans _and_ their tools), +the library focuses on offering a toolset for "human teaming": that is, treating software tools that +are either _teamclients_ or _teamservers_ of others, within a defined -generally refrained- team of +users, which shall generally be strictly and securely authenticated. + +The project originates from the refactoring of a security-oriented tool that used this approach to +clearly segregate client and server binary code (the former's not needing most of the latter's). +Besides, the large exposure of the said-tool to the CLI prompted the author of the +`reeflective/team` library to rethink how the notion of "collaborative programs" could be approached +and explored from different viewpoints: distinguishing between the tools' developers, and their +users. After having to reuse this core code for other projects, the idea appeared to extract the +relevant parts and to restructure and repackage them behind coherent interfaces (API and CLI). + +The result of this refactoring consists in 2 Go packages (`client` and `server`) for programs needing to +act as: +- A **Team client**: a program, or one of its components, that needs to rely on a "remote" program peer + to serve some functionality that is available to a team of users' tools. The program acting as a + _teamclient_ may do so for things as simple as sending a message to the team, or as complicated as a + compiler backend with which multiple client programs can send data to process and build. +- A **Team server**: The remote, server-side counterpart of the software teamclient. Again, the + teamserver can be doing anything, from simply notifying users' teamclient connections to all the team + all the way to handling very complex and resource-hungry tasks that can only be ran on a server host. + +Throughout this library and its documentation, various words are repeatedly employed: +- _teamclient_ refers to either the client-specific toolset provided by this library + (`team/client.Client` core type) or the software making use of this teamclient code. +- _teamserver_ refers to either the server-specific toolset provided to make a program serve its + functionality remotely, or to the tools embedding this code in order to do so. +- _team tool/s_ might be used to refer to programs using either or all of the library components at + large. ----- ## Purposes, Constraints and Features The library rests on several principles, constraints and ideas to fulfill its intended purpose: -- The library's sole aim is to **make most programs able to collaborate together** under the paradigm of team clients - and team servers, and to do so while ensuring performance, coherence, ease of use and security of all processes - and workflows involved. This, under the _separate viewpoints_ of tool development, enhancement and usage. -- Ensure a **working-by-default toolset**, assuming that the time spent on any tool's configuration is inversely - proportional to its usage. Emphasis on this aspect should apply equally well to team tools' users and developers. -- **Accomodate for the needs of developers to use more specific components**, at times or at points, while not hampering - on the working-by-default aspects of the team client/server toolset. Examples include replacing parts or all of the - transport, RPC, loggers, database and filesystem backends. -- To that effect, the library **offer different interfaces to its functionality**: an API (Go code) aiming to provide - developers a working-by-default, simple but powerful way to instruct their software how to collaborate with peers. - +- The library's sole aim is to **make most programs able to collaborate together** under the + paradigm of team clients and team servers, and to do so while ensuring performance, coherence, + ease of use and security of all processes and workflows involved. This, under the _separate + viewpoints_ of tool development, enhancement and usage. +- Ensure a **working-by-default toolset**, assuming that the time spent on any tool's configuration + is inversely proportional to its usage. Emphasis on this aspect should apply equally well to team + tools' users and developers. +- Ensure the **full, secure and reliable authentication of all team clients and servers' + interactions**, by using certificate-based communication encryption and user authentication, _aka_ + a "zero-trust" model. Related and equally important, ensure the various team toolset interfaces + provide for easy and secure usage of their host tools. +- **Accomodate for the needs of developers to use more specific components**, at times or at points, + while not hampering on the working-by-default aspects of the team client/server toolset. Examples + include replacing parts or all of the transport, RPC, loggers, database and filesystem + backends. +- To that effect, the library **offer different interfaces to its functionality**: an API (Go code) + aiming to provide developers a working-by-default, simple but powerful way to instruct their + software how to collaborate with peers. + +Related or resulting from the above, below are examples of behavior adopted by this library: +- All errors returned by the API are always logged before return (with configured log behavior). +- Interactions with the filesystem restrained until they need to happen. +- The default database is a pure Go file-based sqlite db, which can be configured to run in memory. +- Unless absolutely needed or specified otherwise, return all critical errors instead of log + fatal/panicking (exception made of the certificate infrastructure which absolutely needs to work + for security reasons). ----- ## CLI examples (users) @@ -105,15 +131,17 @@ The library rests on several principles, constraints and ideas to fulfill its in ----- ## Differences with Hashicorp Go plugin system -At first glance, different and not much related to our current topic is the equally large problem of dynamic code -loading and execution for arbitrary programs. In the spectrum of major programming languages, various approaches -have been taken to tackle the dynamic linking, loading and execution problem, with interpreted languages offering -the most common solutioning approach to this. - -The Go language (and many other compiled languages that do not encourage dynamic linking for that matter) has to deal with -the problem through other means, the first of which simply being the adoption of different architectural designs in the -first place (eg. "microservices"). Another path has been the "plugin system" for emulating the dynamic workflows of interpreted -languages, of which the most widely used attempt being the [Hashicorp plugin system](https://github.com/hashicorp/go-plugin), which entirely rests on an (g)RPC backend. +At first glance, different and not much related to our current topic is the equally large problem of +dynamic code loading and execution for arbitrary programs. In the spectrum of major programming +languages, various approaches have been taken to tackle the dynamic linking, loading and execution +problem, with interpreted languages offering the most common solutioning approach to this. + +The Go language (and many other compiled languages that do not encourage dynamic linking for that +matter) has to deal with the problem through other means, the first of which simply being the +adoption of different architectural designs in the first place (eg. "microservices"). Another path +has been the "plugin system" for emulating the dynamic workflows of interpreted languages, of which +the most widely used attempt being the [Hashicorp plugin +system](https://github.com/hashicorp/go-plugin), which entirely rests on an (g)RPC backend. ----- From c67f6acef1570c16fb989c6a58ec92995d8b857e Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 13:23:34 +0200 Subject: [PATCH 09/40] README --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index daa23df..12600c3 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,7 @@ and explored from different viewpoints: distinguishing between the tools' develo users. After having to reuse this core code for other projects, the idea appeared to extract the relevant parts and to restructure and repackage them behind coherent interfaces (API and CLI). -The result of this refactoring consists in 2 Go packages (`client` and `server`) for programs needing to -act as: +The result consists in 2 Go packages (`client` and `server`) for programs needing to act as: - A **Team client**: a program, or one of its components, that needs to rely on a "remote" program peer to serve some functionality that is available to a team of users' tools. The program acting as a _teamclient_ may do so for things as simple as sending a message to the team, or as complicated as a @@ -107,9 +106,13 @@ The library rests on several principles, constraints and ideas to fulfill its in while not hampering on the working-by-default aspects of the team client/server toolset. Examples include replacing parts or all of the transport, RPC, loggers, database and filesystem backends. -- To that effect, the library **offer different interfaces to its functionality**: an API (Go code) - aiming to provide developers a working-by-default, simple but powerful way to instruct their - software how to collaborate with peers. +- To that effect, the library offers **different interfaces to its functionality**: an API (Go code) + aiming to provide developers a working-by-default, simple and powerful way to instruct their + software how to collaborate with peers, and a CLI, for users to operate their team tools, manage + their related team configurations with ease, with a featured command-line tree to embed anywhere. +- Ensure that team client/server functionality can be **easily integrated in automated workflows**: + this is done by offering clear code/execution paths and behaviors, for both users and developers, + and by providing commands and functions to ease deployment of said tools. Related or resulting from the above, below are examples of behavior adopted by this library: - All errors returned by the API are always logged before return (with configured log behavior). @@ -120,10 +123,50 @@ Related or resulting from the above, below are examples of behavior adopted by t for security reasons). ----- -## CLI examples (users) +## CLI (users) + +The following extracts assume a program binary named `teamserver`, which is simply the root command +of the server-side team code. In this case therefore, the binary program only purpose its to be a +teamserver, with no application-specific logic, and is useless on its own: +```bash +$ teamserver +Manage the application server-side teamserver and users + +Usage: + teamserver [command] + +teamserver control + client Client-only teamserver commands (import configs, show users, etc) + close Close a listener and remove it from persistent ones if it's one + daemon Start the teamserver in daemon mode (blocking) + listen Start a teamserver listener (non-blocking) + status Show the status of the teamserver (listeners, configurations, health...) + systemd Print a systemd unit file for the application teamserver, with options + +user management + delete Remove a user from the teamserver, and revoke all its current tokens + export Export a Certificate Authority file containing the teamserver users + import Import a certificate Authority file containing teamserver users + user Create a user for this teamserver and generate its client configuration file +``` + +In this example, this program comes with a client-only binary counterpart, `teamclient`. The latter +does not include any team server-specific code, and has therefore a much smaller command set: +```bash +$ teamclient +Client-only teamserver commands (import configs, show users, etc) + +Usage: + teamclient [command] + +Available Commands: + import Import a teamserver client configuration file for teamserver + users Display a table of teamserver users and their status + version Print teamserver client version +``` ----- -## API examples (developers) +## API (developers) ----- ## Documentation From 68800158afdc617af954e482bb90be7f7e575b87 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 15:59:17 +0200 Subject: [PATCH 10/40] Add code examples to readme --- README.md | 83 +++++++++++++++++++++++++++++++++++--- example/teamserver/main.go | 3 +- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 12600c3..6b9ae74 100644 --- a/README.md +++ b/README.md @@ -107,9 +107,9 @@ The library rests on several principles, constraints and ideas to fulfill its in include replacing parts or all of the transport, RPC, loggers, database and filesystem backends. - To that effect, the library offers **different interfaces to its functionality**: an API (Go code) - aiming to provide developers a working-by-default, simple and powerful way to instruct their - software how to collaborate with peers, and a CLI, for users to operate their team tools, manage - their related team configurations with ease, with a featured command-line tree to embed anywhere. + provides developers a working-by-default, simple and powerful way to instruct their software how + to collaborate with peers, and a CLI, for users to operate their team tools, manage their related + team configurations with ease, with a featured command-line tree to embed anywhere. - Ensure that team client/server functionality can be **easily integrated in automated workflows**: this is done by offering clear code/execution paths and behaviors, for both users and developers, and by providing commands and functions to ease deployment of said tools. @@ -128,7 +128,7 @@ Related or resulting from the above, below are examples of behavior adopted by t The following extracts assume a program binary named `teamserver`, which is simply the root command of the server-side team code. In this case therefore, the binary program only purpose its to be a teamserver, with no application-specific logic, and is useless on its own: -```bash +``` $ teamserver Manage the application server-side teamserver and users @@ -152,7 +152,7 @@ user management In this example, this program comes with a client-only binary counterpart, `teamclient`. The latter does not include any team server-specific code, and has therefore a much smaller command set: -```bash +``` $ teamclient Client-only teamserver commands (import configs, show users, etc) @@ -165,9 +165,82 @@ Available Commands: version Print teamserver client version ``` +With these example binaries at hand, below are some examples of workflows. +Starting with the `teamserver` binary (which might be under access/control of a team admin): +``` bash +# Example 1 - Generate a user for a local teamserver, and import users from a file. + +# Example 2 - Start some teamserver listeners, then start the teamserver daemon (blocking). + +# Example 3 - Export and enable a systemd service configuration for the teamserver. + +# Example 4 - Import the "remote" administrator configuration for (1), and use it. +``` + +Continuing the `teamclient` binary (which is available to all users' tool in the team): +```bash +# Example 1 - Import a remote teamserver configuration file given by a team administrator. + +# Example 2 - Query the server for its information. +``` + ----- ## API (developers) +The teamclient and teamserver APIs are designed with several things in mind as well: +- While users are free to use their tools teamclients/servers within the bounds of the provided + command-line interface tree (`teamserver` and `teamclient` commands), the developers using the + library have access to a slightly larger API, especially with regards to "selection strategies" + (grossly, the way tools' teamclients choose their remote teamservers before connecting to them). + This is equivalent of saying that tools developers should have identified 70% of all different + scenarios/valid operation mode for their tools, and program their teamclients accounting for this, + but let the users decide of the remaining 30% when using the tools teamclient/server CLI commands. +- The library makes it easy to embed a teamclient or a teamserver in existing codebases, or easy to + include it in the ones who will need it in the future. In any case, importing and using a default + teamclient/teamserver should fit into a couple of function calls at most. +- To provide a documented code base, with a concise naming and programming model which allows equally + well to use default teamclient backends or to partially/fully reimplement different layers. + +Below is the simplest, shortest example of the above's `teamserver` binary `main()` function: +```go +// Generate a teamserver, without any specific transport/RPC backend. +// Such backends are only needed when the teamserver serves remote clients. +teamserver, err := server.New("teamserver") + +// Generate a tree of server-side commands: this tree also has client-only +// commands as a subcommand "client" of the "teamserver" command root here. +serverCmds := commands.Generate(teamserver, teamserver.Self()) + +// Run the teamserver CLI. +serverCmds.Execute() +``` + +Another slightly more complex example, involving a gRPC transport/RPC backend: +```go +// The examples directory has a default teamserver listener backend. +gTeamserver := grpc.NewListener() + +// Create a new teamserver, register the gRPC backend with it. +// All gRPC teamclients will be able to connect to our teamserver. +teamserver, err := server.New("teamserver", server.WithListener(gTeamserver)) + +// Since our teamserver offers its functionality through a gRPC layer, +// our teamclients must have the corresponding client-side RPC client backend. +// Create a gRPC teamclient backend. +gTeamclient := grpc.NewClientFrom(gTeamserver) + +// Create a new teamclient, registering the gRPC backend to it. +teamclient := teamserver.Self(client.WithDialer(gTeamclient)) + +// Generate the commands for the teamserver. +serverCmds := commands.Generate(teamserver, teamclient) + +// Run any of the commands. +serverCmds.Execute() +``` + +Please see the [example](https://github.com/reeflective/team/tree/main/example) directory for all client/server entrypoint examples. + ----- ## Documentation diff --git a/example/teamserver/main.go b/example/teamserver/main.go index 61803af..ca67e22 100644 --- a/example/teamserver/main.go +++ b/example/teamserver/main.go @@ -3,12 +3,11 @@ package main import ( "log" - "github.com/rsteube/carapace" - "github.com/reeflective/team/client" grpc "github.com/reeflective/team/example/transports/grpc/server" "github.com/reeflective/team/server" "github.com/reeflective/team/server/commands" + "github.com/rsteube/carapace" ) // main shows how to use a teamserver and teamclient with gRPC backends (transport & RPC). From ee2f75b0670c78455bd89e5125124e5f4625e6e8 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 16:16:00 +0200 Subject: [PATCH 11/40] README --- README.md | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 6b9ae74..980139d 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ The `reeflective/team` library provides a small toolset for arbitrary programs ( controlled in more or less interactive ways) to collaborate together by acting as clients and servers of each others, as part of a team. Teams being made of players (humans _and_ their tools), the library focuses on offering a toolset for "human teaming": that is, treating software tools that -are either _teamclients_ or _teamservers_ of others, within a defined -generally refrained- team of +are either _teamclients_ or _teamservers_ of others, within a defined -generally restricted- team of users, which shall generally be strictly and securely authenticated. The project originates from the refactoring of a security-oriented tool that used this approach to @@ -100,7 +100,7 @@ The library rests on several principles, constraints and ideas to fulfill its in tools' users and developers. - Ensure the **full, secure and reliable authentication of all team clients and servers' interactions**, by using certificate-based communication encryption and user authentication, _aka_ - a "zero-trust" model. Related and equally important, ensure the various team toolset interfaces + "zero-trust" model. Related and equally important, ensure the various team toolset interfaces provide for easy and secure usage of their host tools. - **Accomodate for the needs of developers to use more specific components**, at times or at points, while not hampering on the working-by-default aspects of the team client/server toolset. Examples @@ -114,16 +114,8 @@ The library rests on several principles, constraints and ideas to fulfill its in this is done by offering clear code/execution paths and behaviors, for both users and developers, and by providing commands and functions to ease deployment of said tools. -Related or resulting from the above, below are examples of behavior adopted by this library: -- All errors returned by the API are always logged before return (with configured log behavior). -- Interactions with the filesystem restrained until they need to happen. -- The default database is a pure Go file-based sqlite db, which can be configured to run in memory. -- Unless absolutely needed or specified otherwise, return all critical errors instead of log - fatal/panicking (exception made of the certificate infrastructure which absolutely needs to work - for security reasons). - ----- -## CLI (users) +## CLI (Users) The following extracts assume a program binary named `teamserver`, which is simply the root command of the server-side team code. In this case therefore, the binary program only purpose its to be a @@ -185,7 +177,7 @@ Continuing the `teamclient` binary (which is available to all users' tool in the ``` ----- -## API (developers) +## API (Developers) The teamclient and teamserver APIs are designed with several things in mind as well: - While users are free to use their tools teamclients/servers within the bounds of the provided @@ -226,7 +218,7 @@ teamserver, err := server.New("teamserver", server.WithListener(gTeamserver)) // Since our teamserver offers its functionality through a gRPC layer, // our teamclients must have the corresponding client-side RPC client backend. -// Create a gRPC teamclient backend. +// Create an in-memory gRPC teamclient backend for the server to serve itself. gTeamclient := grpc.NewClientFrom(gTeamserver) // Create a new teamclient, registering the gRPC backend to it. @@ -239,11 +231,24 @@ serverCmds := commands.Generate(teamserver, teamclient) serverCmds.Execute() ``` +Some additional and preliminary/example notes about the codebase: +- All errors returned by the API are always logged before return (with configured log behavior). +- Interactions with the filesystem restrained until they need to happen. +- The default database is a pure Go file-based sqlite db, which can be configured to run in memory. +- Unless absolutely needed or specified otherwise, return all critical errors instead of log + fatal/panicking (exception made of the certificate infrastructure which absolutely needs to work + for security reasons). + Please see the [example](https://github.com/reeflective/team/tree/main/example) directory for all client/server entrypoint examples. ----- ## Documentation +Go code documentation is available at https://pkg.go.dev/github.com/reeflective/team. +Client and server documentation can found in the [directories section](https://pkg.go.dev/github.com/reeflective/team#section-directories) of the Go documentation. +The `example/` subdirectories also include documentation for their own code, and should provide +a good introduction to this library usage. + ----- ## Differences with Hashicorp Go plugin system From 48fc6a452c8827a153d9fcc94c0c9d0d06a60f6f Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 16:28:02 +0200 Subject: [PATCH 12/40] README Examples --- README.md | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 980139d..997c9c0 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,10 @@ and explored from different viewpoints: distinguishing between the tools' develo users. After having to reuse this core code for other projects, the idea appeared to extract the relevant parts and to restructure and repackage them behind coherent interfaces (API and CLI). + +----- +## Components & Terms + The result consists in 2 Go packages (`client` and `server`) for programs needing to act as: - A **Team client**: a program, or one of its components, that needs to rely on a "remote" program peer to serve some functionality that is available to a team of users' tools. The program acting as a @@ -88,7 +92,7 @@ Throughout this library and its documentation, various words are repeatedly empl large. ----- -## Purposes, Constraints and Features +## Principles, Constraints & Features The library rests on several principles, constraints and ideas to fulfill its intended purpose: - The library's sole aim is to **make most programs able to collaborate together** under the @@ -160,20 +164,39 @@ Available Commands: With these example binaries at hand, below are some examples of workflows. Starting with the `teamserver` binary (which might be under access/control of a team admin): ``` bash -# Example 1 - Generate a user for a local teamserver, and import users from a file. - -# Example 2 - Start some teamserver listeners, then start the teamserver daemon (blocking). - -# Example 3 - Export and enable a systemd service configuration for the teamserver. - -# Example 4 - Import the "remote" administrator configuration for (1), and use it. +# 1 - Generate a user for a local teamserver, and import users from a file. +teamserver user --name Michael --host localhost +teamserver import ~/.other_app/teamserver/certs/other_app_user-ca-cert.teamserver.pem + +# 2 - Start some teamserver listeners, then start the teamserver daemon (blocking). +# Use the application-defined default port in the first call, and instruct the server +# to start the listeners automatically when used in daemon mode with --persistent. +teamserver listen --host localhost --persistent +teamserver listen --host 172.10.0.10 --port 32333 --persistent +teamserver status # Prints the saved listeners, configured loggers, databases, etc. + +# 3 - Export and enable a systemd service configuration for the teamserver. +teamserver systemd # Use default host, port and listener stacks. +teamserver systemd --host localhost --binpath /path/to/teamserver # Specify binary path. +teamserver systemd --user --save ~/teamserver.service # Print to file instead of stdout. + +# 4 - Import the "remote" administrator configuration for (1), and use it. +teamserver client import ~/Michael_localhost.teamclient.cfg +teamserver client version # Print the client and the server version information. +teamserver client users # Print all users registered to the teamserver and their status. + +# 5 - Quality of life +teamserver _carapace # Source detailed the completion engine for the teamserver. ``` Continuing the `teamclient` binary (which is available to all users' tool in the team): ```bash # Example 1 - Import a remote teamserver configuration file given by a team administrator. +teamclient import ~/Michael_localhost.teamclient.cfg # Example 2 - Query the server for its information. +teamclient users +teamclient version ``` ----- From e403916dc3fb51f3211001a08ae2029941378710 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 17:47:21 +0200 Subject: [PATCH 13/40] README --- README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 997c9c0..1c5165a 100644 --- a/README.md +++ b/README.md @@ -173,17 +173,17 @@ teamserver import ~/.other_app/teamserver/certs/other_app_user-ca-cert.teamserve # to start the listeners automatically when used in daemon mode with --persistent. teamserver listen --host localhost --persistent teamserver listen --host 172.10.0.10 --port 32333 --persistent -teamserver status # Prints the saved listeners, configured loggers, databases, etc. +teamserver status # Prints the saved listeners, configured loggers, databases, etc. # 3 - Export and enable a systemd service configuration for the teamserver. -teamserver systemd # Use default host, port and listener stacks. -teamserver systemd --host localhost --binpath /path/to/teamserver # Specify binary path. -teamserver systemd --user --save ~/teamserver.service # Print to file instead of stdout. +teamserver systemd # Use default host, port and listener stacks. +teamserver systemd --host localhost --binpath /path/to/teamserver # Specify binary path. +teamserver systemd --user --save ~/teamserver.service # Print to file instead of stdout. # 4 - Import the "remote" administrator configuration for (1), and use it. -teamserver client import ~/Michael_localhost.teamclient.cfg -teamserver client version # Print the client and the server version information. -teamserver client users # Print all users registered to the teamserver and their status. +teamserver client import ~/Michael_localhost.teamclient.cfg +teamserver client version # Print the client and the server version information. +teamserver client users # Print all users registered to the teamserver and their status. # 5 - Quality of life teamserver _carapace # Source detailed the completion engine for the teamserver. @@ -261,19 +261,25 @@ Some additional and preliminary/example notes about the codebase: - Unless absolutely needed or specified otherwise, return all critical errors instead of log fatal/panicking (exception made of the certificate infrastructure which absolutely needs to work for security reasons). +- Exception made of the `teamserver daemon` command related `server.ServeDaemon` function, all API + functions and interface methods are non-blocking. Mentions of this are found throughout the + code documentation when needed. +- Loggers offered by the teamclient/server cores are never nil, and will log to both stdout (above + warning level) and to default files (above info level) if no custom logger is passed to them. + If such a custom logger is given, team clients/servers won't log to stdout or their default files. Please see the [example](https://github.com/reeflective/team/tree/main/example) directory for all client/server entrypoint examples. ----- ## Documentation -Go code documentation is available at https://pkg.go.dev/github.com/reeflective/team. -Client and server documentation can found in the [directories section](https://pkg.go.dev/github.com/reeflective/team#section-directories) of the Go documentation. -The `example/` subdirectories also include documentation for their own code, and should provide +- Go code documentation is available at the [Godoc website](https://pkg.go.dev/github.com/reeflective/team). +- Client and server documentation can be found in the [directories section](https://pkg.go.dev/github.com/reeflective/team#section-directories) of the Go documentation. +- The `example/` subdirectories also include documentation for their own code, and should provide a good introduction to this library usage. ----- -## Differences with Hashicorp Go plugin system +## Differences with the Hashicorp Go plugin system At first glance, different and not much related to our current topic is the equally large problem of dynamic code loading and execution for arbitrary programs. In the spectrum of major programming From 81f898e664899edc8767bb3c9ea07f1f570bd93d Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 18:03:14 +0200 Subject: [PATCH 14/40] Differences with Hashicorp plugins --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c5165a..c3c5fcb 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ The library rests on several principles, constraints and ideas to fulfill its in The following extracts assume a program binary named `teamserver`, which is simply the root command of the server-side team code. In this case therefore, the binary program only purpose its to be a -teamserver, with no application-specific logic, and is useless on its own: +teamserver, with no application-specific logic, (and is therefore quite useless on its own): ``` $ teamserver Manage the application server-side teamserver and users @@ -174,6 +174,7 @@ teamserver import ~/.other_app/teamserver/certs/other_app_user-ca-cert.teamserve teamserver listen --host localhost --persistent teamserver listen --host 172.10.0.10 --port 32333 --persistent teamserver status # Prints the saved listeners, configured loggers, databases, etc. +teamserver daemon --host localhost --port 31337 # Blocking: serves all persistent listeners and a main one at localhost:31337 # 3 - Export and enable a systemd service configuration for the teamserver. teamserver systemd # Use default host, port and listener stacks. @@ -293,6 +294,25 @@ has been the "plugin system" for emulating the dynamic workflows of interpreted the most widely used attempt being the [Hashicorp plugin system](https://github.com/hashicorp/go-plugin), which entirely rests on an (g)RPC backend. +Consequently, differences and similarities can be resumed as follows: +- The **Hashicorp plugins only support "remote" plugins** in that each plugin must be a different + binary. Although those plugins seem to be executed "in-memory", they are not. On the contrary, + the `reeflective/team` clients and servers can (should, and will) be used both in memory and + remotely (here remotely means as a distinct subprocess: actual network location is irrelevant). +- The purpose of the `reeflective/team` library is **not** to emulate dynamic code execution behavior. + Rather, its intent is to make programs that should or might be better used as servers to several + clients to act as such easily and securely in many different scenarios. +- The **Hashicorp plugins are by essence restrained to an API problem**, and while the `team` library + is equally (but not mandatorily or exclusively) about interactive usage of arbitrary programs. +- **The Hashicorp plugin relies mandatorily (since it's built on) a gRPC transport backend**. While + gRPC is a very sensible choice for many reasons (and is therefore used for the default example + backend in `example/transports/`), the `team` library does not force library users to use a given + transport/RPC backend, nor even to use one. Again, this would be beyond the library scope, but + what is in scope is the capacity of this library to interface with or use different transports. +- Finally, the Hashicorp plugins are not aware of any concept of users as they are considered by + the team library, although both use certificate-based connections. However, `team` promotes and + makes easy to use mutually authenticated (Mutual TLS) connections (see the default gRPC example + backend). Related to this, teamservers integrate loggers and a database to store working data. ----- ## Status From dd0e5775f12b1eaa7b58220160df25efe1f8474a Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 18:23:46 +0200 Subject: [PATCH 15/40] Add README to example --- example/README.md | 39 ++++++++++++++++++++ example/transports/grpc/server/middleware.go | 5 +-- example/transports/grpc/server/server.go | 7 ++-- 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 example/README.md diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..2d0f146 --- /dev/null +++ b/example/README.md @@ -0,0 +1,39 @@ + +## Examples + +This directory contains several example components or programs leveraging teamclients and/or teamservers. +Each of the packages' code is documented to the best extent possible, and structured accordingly. +The author hopes that by entering the code by the `main()` function and reading carefully through will +be enough for most library users to get a good first grasp of the `team` library programming model. + +### 1) General workflow & entrypoints + +Therefore, users should probably start reading those files in order: +1) `teamserver/main.go` shows several examples of server-side program entrypoints, with varying + transports, behaviors, backends and options. +2) `teamclient/main.go` shows some equivalent examples for teamclient-only programs. These functions + are a counterpart to some of those found in (1), as they use the same transport/RPC stack. + +### 2) Transport backends + +#### Team Server +Once you feel having a good understanding of entrypoints (server/client creation, setup, CLI generation +and related), you can then take a look at the transport backends mechanism, which allows to register any +number of transport/RPC listener/server backends to your core application teamserver: +3) `transports/grpc/server/server.go` is used by the `teamserver/main.go` to create and prepare a new + RPC backend. This file is good in that it shows you clearly how to use the teamserver as a core + driver for any application-specific teamserving process. For example it shows how to query the + teamserver users, request their connection/token credentials, authenticate them, and log all steps + with the teamserver loggers. +4) `transports/grpc/server/middleware.go` shows a quite complex but secure use of gRPC middleware using + the teamserver authentication and logging toolset. Note that gRPC is a quite beefy stack, and not + very idiomatic for Go. Don't be too scared at this code if you don't understand it at first, since + it's very likely that you will either decide to use it as is (or mostly), or that you will opt for + simpler transport backends to plug onto your teamservers. + +#### Team Client +5) `transports/grpc/client/client.go` is used by the `teamclient/main.go` to create and prepare the gRPC + counterpart to the server backend previously mentioned, using similar APIs to setup authentication, + encryption and logging, and implementing the dialer backend in the same fashion. +6) `transports/grpc/client/middleware.go` is very much identical in form and intents to its + `transports/grpc/server/middleware.go` counterpart. diff --git a/example/transports/grpc/server/middleware.go b/example/transports/grpc/server/middleware.go index 043fd44..c207bc3 100644 --- a/example/transports/grpc/server/middleware.go +++ b/example/transports/grpc/server/middleware.go @@ -25,14 +25,13 @@ import ( grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_tags "github.com/grpc-ecosystem/go-grpc-middleware/tags" + "github.com/reeflective/team/example/transports/grpc/common" + "github.com/reeflective/team/server" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" - - "github.com/reeflective/team/example/transports/grpc/common" - "github.com/reeflective/team/server" ) // BufferingOptions returns a list of server options with max send/receive diff --git a/example/transports/grpc/server/server.go b/example/transports/grpc/server/server.go index 421b6a1..8c9b850 100644 --- a/example/transports/grpc/server/server.go +++ b/example/transports/grpc/server/server.go @@ -24,13 +24,12 @@ import ( "runtime/debug" "sync" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/test/bufconn" - clientConn "github.com/reeflective/team/example/transports/grpc/client" "github.com/reeflective/team/example/transports/grpc/proto" teamserver "github.com/reeflective/team/server" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" ) const ( From 4c4dd5f1e113d7c56e5845189b72eb0d58e7ec93 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 18:32:55 +0200 Subject: [PATCH 16/40] README --- example/README.md | 14 +++++++++++--- server/db.go | 14 ++++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/example/README.md b/example/README.md index 2d0f146..c34e606 100644 --- a/example/README.md +++ b/example/README.md @@ -6,7 +6,14 @@ Each of the packages' code is documented to the best extent possible, and struct The author hopes that by entering the code by the `main()` function and reading carefully through will be enough for most library users to get a good first grasp of the `team` library programming model. -### 1) General workflow & entrypoints +Overall, the example directory can serve two purposes: +- To serve as an example usage of the library, with different directories showing how to use + different components, as well as how they make use the teamserver/clients core in their own way. +- To be outright copy-pasted in your own code structure and modified where needed. + This should possible to the extent that the code has been rewritten to have sensible + fallback behavior, to log its various steps and errors, and to fail earlier rather later. + +### I - General workflow & entrypoints Therefore, users should probably start reading those files in order: 1) `teamserver/main.go` shows several examples of server-side program entrypoints, with varying @@ -14,17 +21,18 @@ Therefore, users should probably start reading those files in order: 2) `teamclient/main.go` shows some equivalent examples for teamclient-only programs. These functions are a counterpart to some of those found in (1), as they use the same transport/RPC stack. -### 2) Transport backends +### II - Transport backends #### Team Server Once you feel having a good understanding of entrypoints (server/client creation, setup, CLI generation and related), you can then take a look at the transport backends mechanism, which allows to register any number of transport/RPC listener/server backends to your core application teamserver: + 3) `transports/grpc/server/server.go` is used by the `teamserver/main.go` to create and prepare a new RPC backend. This file is good in that it shows you clearly how to use the teamserver as a core driver for any application-specific teamserving process. For example it shows how to query the teamserver users, request their connection/token credentials, authenticate them, and log all steps - with the teamserver loggers. + with the teamserver loggers. 4) `transports/grpc/server/middleware.go` shows a quite complex but secure use of gRPC middleware using the teamserver authentication and logging toolset. Note that gRPC is a quite beefy stack, and not very idiomatic for Go. Don't be too scared at this code if you don't understand it at first, since diff --git a/server/db.go b/server/db.go index 31bc97c..9ecafe4 100644 --- a/server/db.go +++ b/server/db.go @@ -37,9 +37,10 @@ const ( ) // Database returns a new teamserver database session, which may not be nil: -// at worst, this database will be an in-memory one. The default is a file- -// based Sqlite database in the teamserver directory, but it might be a -// specific database passed through options. +// if no custom database backend was passed to the server at creation time, +// this database will be an in-memory one. The default is a file-based Sqlite +// database in the teamserver directory, but it might be a specific database +// passed through options. func (ts *Server) Database() *gorm.DB { return ts.db.Session(&gorm.Session{ FullSaveAssociations: true, @@ -47,7 +48,7 @@ func (ts *Server) Database() *gorm.DB { } // DatabaseConfig returns the server database backend configuration struct. -// If configuration could be found on disk, the default Sqlite file-based +// If no configuration could be found on disk, the default Sqlite file-based // database is returned, with app-corresponding file paths. func (ts *Server) DatabaseConfig() *db.Config { cfg, err := ts.getDatabaseConfig() @@ -60,9 +61,10 @@ func (ts *Server) DatabaseConfig() *db.Config { // GetDatabaseConfigPath - File path to config.json. func (ts *Server) dbConfigPath() string { - appDir := ts.TeamDir() + appDir := ts.ConfigPath() log := ts.NamedLogger("config", "database") - databaseConfigPath := filepath.Join(appDir, "configs", fmt.Sprintf("%s.%s", ts.Name()+"_database", command.ServerConfigExt)) + dbFileName := fmt.Sprintf("%s.%s", ts.Name()+"_database", command.ServerConfigExt) + databaseConfigPath := filepath.Join(appDir, dbFileName) log.Debugf("Loading config from %s", databaseConfigPath) return databaseConfigPath From d0a84a292a8ee09adf6f0265e3d5341d0508fb3d Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 18:40:37 +0200 Subject: [PATCH 17/40] README --- example/README.md | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/example/README.md b/example/README.md index c34e606..bce37d7 100644 --- a/example/README.md +++ b/example/README.md @@ -1,5 +1,5 @@ -## Examples +# Examples This directory contains several example components or programs leveraging teamclients and/or teamservers. Each of the packages' code is documented to the best extent possible, and structured accordingly. @@ -13,7 +13,33 @@ Overall, the example directory can serve two purposes: This should possible to the extent that the code has been rewritten to have sensible fallback behavior, to log its various steps and errors, and to fail earlier rather later. -### I - General workflow & entrypoints +## Exploring examples as a tool user + +Since this library is about enabling users to "team-connect" their tools to make them collaborate, +you can also test this library from this user perspective by installing the examples as binaries +and toying with them: + +```bash +# Install the teamserver and teamclients. +go install github.com/reeflective/team/example/teamserver +go install github.com/reeflective/team/example/teamclient + +# Install the completion engine and source both tools' scripts (optional) +# See this project documentation for setup with your own shell. Below is bash/zsh. +go install github.com/rsteube/carapace-bin@latest +source <(teamserver _carapace) +source <(teamclient _carapace) + +# Use the tools +teamserver status +teamserver user --name Michael --host localhost +teamclient import Michael_localhost.teamclient.cfg + +teamserver daemon & +teamclient version +``` + +## I - General workflow & entrypoints Therefore, users should probably start reading those files in order: 1) `teamserver/main.go` shows several examples of server-side program entrypoints, with varying @@ -21,9 +47,9 @@ Therefore, users should probably start reading those files in order: 2) `teamclient/main.go` shows some equivalent examples for teamclient-only programs. These functions are a counterpart to some of those found in (1), as they use the same transport/RPC stack. -### II - Transport backends +## II - Transport backends -#### Team Server +### Team Server Once you feel having a good understanding of entrypoints (server/client creation, setup, CLI generation and related), you can then take a look at the transport backends mechanism, which allows to register any number of transport/RPC listener/server backends to your core application teamserver: @@ -39,7 +65,7 @@ number of transport/RPC listener/server backends to your core application teamse it's very likely that you will either decide to use it as is (or mostly), or that you will opt for simpler transport backends to plug onto your teamservers. -#### Team Client +### Team Client 5) `transports/grpc/client/client.go` is used by the `teamclient/main.go` to create and prepare the gRPC counterpart to the server backend previously mentioned, using similar APIs to setup authentication, encryption and logging, and implementing the dialer backend in the same fashion. From deac49559c0ff9917a1f91becd9beeeaaff666db Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 18:55:57 +0200 Subject: [PATCH 18/40] Update ncruces/sqlite dependencies --- go.mod | 17 +++++++++-------- go.sum | 35 +++++++++++++++++++++++------------ internal/db/sql-cgo.go | 5 ++++- internal/db/sql-go.go | 5 +++-- internal/db/sql.go | 2 +- 5 files changed, 40 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index f1cd7bd..d6619c5 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,15 @@ module github.com/reeflective/team -go 1.20 +go 1.21 + +toolchain go1.21.0 require ( - github.com/glebarez/sqlite v1.8.0 github.com/gofrs/uuid v4.4.0+incompatible github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/jedib0t/go-pretty/v6 v6.4.6 - github.com/mattn/go-sqlite3 v1.14.17 - github.com/ncruces/go-sqlite3 v0.8.1 + github.com/ncruces/go-sqlite3 v0.8.4 + github.com/ncruces/go-sqlite3/gormlite v0.8.4 github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e github.com/rsteube/carapace v0.37.3 github.com/sirupsen/logrus v1.9.3 @@ -26,7 +27,6 @@ require ( require ( github.com/dustin/go-humanize v1.0.1 // indirect - github.com/glebarez/go-sqlite v1.21.1 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/google/uuid v1.3.0 // indirect @@ -40,18 +40,19 @@ require ( github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/ncruces/julianday v0.1.5 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/stretchr/testify v1.8.2 // indirect - github.com/tetratelabs/wazero v1.2.1 // indirect + github.com/tetratelabs/wazero v1.4.0 // indirect golang.org/x/crypto v0.8.0 // indirect golang.org/x/mod v0.11.0 // indirect golang.org/x/net v0.9.0 // indirect - golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/tools v0.6.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 3161901..825f0e9 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.110.0 h1:Zc8gqp3+a9/Eyph2KDmcGaPtbKRIoqq4YTlL4NMD0Ys= cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvuXY= +cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= @@ -20,10 +22,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/glebarez/go-sqlite v1.21.1 h1:7MZyUPh2XTrHS7xNEHQbrhfMZuPSzhkm2A1qgg0y5NY= -github.com/glebarez/go-sqlite v1.21.1/go.mod h1:ISs8MF6yk5cL4n/43rSOmVMGJJjHYr7L2MbZZ5Q4E2E= -github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc= -github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= @@ -45,7 +43,9 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= @@ -73,6 +73,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -91,8 +92,10 @@ github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6 github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/ncruces/go-sqlite3 v0.8.1 h1:e1Y7uHu96xC4fWKsCVWprbTi8vAaQX9R+8kgkxOHWaY= -github.com/ncruces/go-sqlite3 v0.8.1/go.mod h1:EhHe1qvG6Zc/8ffYMzre8n//rTRs1YNN5dUD1f1mEGc= +github.com/ncruces/go-sqlite3 v0.8.4 h1:nizhgJMMJJBrthESCwF30+oOvQkdtizgJ/v35Y0v+vg= +github.com/ncruces/go-sqlite3 v0.8.4/go.mod h1:XvDtjKk5MgwHX7L4I7BPzzKl36bTZ7+Hr6Kr2QeVkVw= +github.com/ncruces/go-sqlite3/gormlite v0.8.4 h1:omeGR0XofGGwlbWB5QSEdPQC0j58fDEULrVMLXTIt+M= +github.com/ncruces/go-sqlite3/gormlite v0.8.4/go.mod h1:52uZNxrd8iQVjmxE6l3Dt71zoHpwnoDDFIqB1wW1+Cg= github.com/ncruces/julianday v0.1.5 h1:hDJ9ejiMp3DHsoZ5KW4c1lwfMjbARS7u/gbYcd0FBZk= github.com/ncruces/julianday v0.1.5/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -134,8 +137,8 @@ github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/tetratelabs/wazero v1.2.1 h1:J4X2hrGzJvt+wqltuvcSjHQ7ujQxA9gb6PeMs4qlUWs= -github.com/tetratelabs/wazero v1.2.1/go.mod h1:wYx2gNRg8/WihJfSDxA1TIL8H+GkfLYm+bIfbblu9VQ= +github.com/tetratelabs/wazero v1.4.0 h1:9/MirYvmkJ/zSUOygKY/ia3t+e+RqIZXKbylIby1WYk= +github.com/tetratelabs/wazero v1.4.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -169,12 +172,14 @@ golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= +golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -188,12 +193,12 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -212,6 +217,7 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -233,6 +239,7 @@ gopkg.in/AlecAivazis/survey.v1 v1.8.8/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -257,7 +264,9 @@ modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0= modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw= modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY= modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk= +modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= +modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= @@ -271,6 +280,8 @@ modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY= +modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c= modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY= +modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE= diff --git a/internal/db/sql-cgo.go b/internal/db/sql-cgo.go index aaedce9..c78e93f 100644 --- a/internal/db/sql-cgo.go +++ b/internal/db/sql-cgo.go @@ -21,7 +21,10 @@ package db */ import ( - _ "github.com/mattn/go-sqlite3" + "github.com/ncruces/go-sqlite3" + _ "github.com/ncruces/go-sqlite3/embed" + + // _ "github.com/mattn/go-sqlite3" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" diff --git a/internal/db/sql-go.go b/internal/db/sql-go.go index 5b35246..7173c6d 100644 --- a/internal/db/sql-go.go +++ b/internal/db/sql-go.go @@ -21,13 +21,14 @@ package db */ import ( - gosqlite "github.com/glebarez/sqlite" + _ "github.com/ncruces/go-sqlite3/embed" + "github.com/ncruces/go-sqlite3/gormlite" "gorm.io/gorm" "gorm.io/gorm/logger" ) func sqliteClient(dsn string, log logger.Interface) (*gorm.DB, error) { - return gorm.Open(gosqlite.Open(dsn), &gorm.Config{ + return gorm.Open(gormlite.Open(dsn), &gorm.Config{ PrepareStmt: true, Logger: log, }) diff --git a/internal/db/sql.go b/internal/db/sql.go index 713862f..00a030b 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -83,7 +83,7 @@ func NewClient(dbConfig *Config, dbLogger *logrus.Entry) (*gorm.DB, error) { return nil, fmt.Errorf("%w: '%s'", ErrUnsupportedDialect, dbConfig.Dialect) } - err = dbClient.AutoMigrate(Schema()) + err = dbClient.AutoMigrate(Schema()...) if err != nil { dbLogger.Error(err) } From 8435ef0567e2f89972c966f679cc091746ef0479 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 18:58:45 +0200 Subject: [PATCH 19/40] Use go1.21 in actions --- .github/workflows/go.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 17a0ecf..4e7fe66 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -23,7 +23,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: 1.20.4 + go-version: 1.21 - name: Version information run: bash teamserver_version_info @@ -59,7 +59,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.20.4 + go-version: 1.21 - name: Version information run: bash teamserver_version_info From 22bce3642d7074c21f817f33887ca27815af2776 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:02:08 +0200 Subject: [PATCH 20/40] Fix cgo build --- internal/db/sql-cgo.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/db/sql-cgo.go b/internal/db/sql-cgo.go index c78e93f..5dd5b81 100644 --- a/internal/db/sql-cgo.go +++ b/internal/db/sql-cgo.go @@ -21,10 +21,9 @@ package db */ import ( - "github.com/ncruces/go-sqlite3" _ "github.com/ncruces/go-sqlite3/embed" - // _ "github.com/mattn/go-sqlite3" + _ "github.com/mattn/go-sqlite3" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" From f77d921bcc2b43c235930346fe0cbf77c8d246ea Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:04:04 +0200 Subject: [PATCH 21/40] Try to fix actions CodeQL --- go.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.mod b/go.mod index d6619c5..bc7ff12 100644 --- a/go.mod +++ b/go.mod @@ -2,8 +2,6 @@ module github.com/reeflective/team go 1.21 -toolchain go1.21.0 - require ( github.com/gofrs/uuid v4.4.0+incompatible github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 From eeb64936f1ab8f4b00e5af4c8525421c3c8d55a0 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:10:15 +0200 Subject: [PATCH 22/40] Tidy comments --- client/client.go | 28 ++++++------- client/commands/commands.go | 80 ++++++++++++++++++------------------- go.mod | 2 +- server/config.go | 6 +-- server/server.go | 10 ++--- server/users.go | 6 +-- 6 files changed, 66 insertions(+), 66 deletions(-) diff --git a/client/client.go b/client/client.go index 9c9e776..44be641 100644 --- a/client/client.go +++ b/client/client.go @@ -39,14 +39,14 @@ import ( // The client also DOES NOT include any teamserver-side code. // // This teamclient core job is to: -// - Fetch, configure and use teamserver endpoint configurations. -// - Drive the process of connecting to & disconnecting from a server. -// - Query a teamserver for its version and users information. +// - Fetch, configure and use teamserver endpoint configurations. +// - Drive the process of connecting to & disconnecting from a server. +// - Query a teamserver for its version and users information. // // Additionally, this client offers: -// - Pre-configured loggers for all client-side related events. -// - Various options to configure its backends and behaviors. -// - A builtin, abstracted and app-specific filesystem (in memory or on disk). +// - Pre-configured loggers for all client-side related events. +// - Various options to configure its backends and behaviors. +// - A builtin, abstracted and app-specific filesystem (in memory or on disk). // // Various combinations of teamclient/teamserver usage are possible. // Please see the Go module example/ directory for a list of them. @@ -79,14 +79,14 @@ type Client struct { // using this dialer, and this clientConn will be provided to these hooks. // // Examples of what this clientConn can be: -// - The clientConn is a specific, but non-idiomatic RPC client (ex: a *grpc.ClientConn). -// - A simple net.Conn over which anything can be done further. -// - Nothing: a dialer might not need to use or even create a client connection. +// - The clientConn is a specific, but non-idiomatic RPC client (ex: a *grpc.ClientConn). +// - A simple net.Conn over which anything can be done further. +// - Nothing: a dialer might not need to use or even create a client connection. type Dialer interface { // Init is used by any dialer to query the teamclient driving it about: - // - The remote teamserver address and transport credentials - // - The user registered in this remote teamserver configuration. - // - To make use of client-side loggers, filesystem and other utilities. + // - The remote teamserver address and transport credentials + // - The user registered in this remote teamserver configuration. + // - To make use of client-side loggers, filesystem and other utilities. Init(c *Client) error // Dial should connect to the endpoint available in any @@ -109,8 +109,8 @@ type Dialer interface { // - When being provided a specific dialer/client/RPC backend. // // The teamclient will only perform a few init things before being returned: -// - Setup its filesystem, either on-disk (default behavior) or in-memory. -// - Initialize loggers and the files they use, if any. +// - Setup its filesystem, either on-disk (default behavior) or in-memory. +// - Initialize loggers and the files they use, if any. // // This may return an error if the teamclient is unable to work with the provided // options (or lack thereof), which may happen if the teamclient cannot use and write diff --git a/client/commands/commands.go b/client/commands/commands.go index 6565187..9f714bd 100644 --- a/client/commands/commands.go +++ b/client/commands/commands.go @@ -139,6 +139,46 @@ func clientCommands(cli *client.Client) *cobra.Command { return teamCmd } +// ConfigsAppCompleter completes file paths to the current application configs. +func ConfigsAppCompleter(cli *client.Client, tag string) carapace.Action { + return carapace.ActionCallback(func(ctx carapace.Context) carapace.Action { + var compErrors []carapace.Action + + configPath := cli.ConfigsDir() + + files, err := os.ReadDir(configPath) + if err != nil { + compErrors = append(compErrors, carapace.ActionMessage("failed to list user directories: %s", err)) + } + + var results []string + + for _, file := range files { + if !strings.HasSuffix(file.Name(), command.ClientConfigExt) { + continue + } + + filePath := filepath.Join(configPath, file.Name()) + + cfg, err := cli.ReadConfig(filePath) + if err != nil || cfg == nil { + continue + } + + results = append(results, filePath) + results = append(results, fmt.Sprintf("[%s] %s:%d", cfg.User, cfg.Host, cfg.Port)) + } + + configsAction := carapace.ActionValuesDescribed(results...).StyleF(getConfigStyle(command.ClientConfigExt)) + + return carapace.Batch(append( + compErrors, + configsAction.Tag(tag), + carapace.ActionFiles())..., + ).ToA() + }) +} + // ConfigsCompleter completes file paths to other teamserver application configs (clients/users CA, etc) // The filepath is the directory between .app/ and the target directory where config files of a certain // type should be found, ext is the normal/default extension for those target files, and tag is used in comps. @@ -199,46 +239,6 @@ func ConfigsCompleter(cli *client.Client, filePath, ext, tag string, noSelf bool } } -// ConfigsAppCompleter completes file paths to the current application configs. -func ConfigsAppCompleter(cli *client.Client, tag string) carapace.Action { - return carapace.ActionCallback(func(ctx carapace.Context) carapace.Action { - var compErrors []carapace.Action - - configPath := cli.ConfigsDir() - - files, err := os.ReadDir(configPath) - if err != nil { - compErrors = append(compErrors, carapace.ActionMessage("failed to list user directories: %s", err)) - } - - var results []string - - for _, file := range files { - if !strings.HasSuffix(file.Name(), command.ClientConfigExt) { - continue - } - - filePath := filepath.Join(configPath, file.Name()) - - cfg, err := cli.ReadConfig(filePath) - if err != nil || cfg == nil { - continue - } - - results = append(results, filePath) - results = append(results, fmt.Sprintf("[%s] %s:%d", cfg.User, cfg.Host, cfg.Port)) - } - - configsAction := carapace.ActionValuesDescribed(results...).StyleF(getConfigStyle(command.ClientConfigExt)) - - return carapace.Batch(append( - compErrors, - configsAction.Tag(tag), - carapace.ActionFiles())..., - ).ToA() - }) -} - func isConfigDir(cli *client.Client, dir fs.DirEntry, noSelf bool) bool { if !strings.HasPrefix(dir.Name(), ".") { return false diff --git a/go.mod b/go.mod index bc7ff12..16d9836 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/gofrs/uuid v4.4.0+incompatible github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/jedib0t/go-pretty/v6 v6.4.6 + github.com/mattn/go-sqlite3 v1.14.17 github.com/ncruces/go-sqlite3 v0.8.4 github.com/ncruces/go-sqlite3/gormlite v0.8.4 github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e @@ -38,7 +39,6 @@ require ( github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect - github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/ncruces/julianday v0.1.5 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect diff --git a/server/config.go b/server/config.go index a155384..25dfb24 100644 --- a/server/config.go +++ b/server/config.go @@ -45,9 +45,9 @@ const ( // // Its default path is ~/.app/teamserver/configs/app.teamserver.cfg. // It uses the following default values: -// - Daemon host: "" -// - Daemon port: 31416 -// - logging file level: Info. +// - Daemon host: "" +// - Daemon port: 31416 +// - logging file level: Info. type Config struct { // When the teamserver command `app teamserver daemon` is executed // without --host/--port flags, the teamserver will use the config. diff --git a/server/server.go b/server/server.go index ad8cb33..a29e055 100644 --- a/server/server.go +++ b/server/server.go @@ -50,9 +50,9 @@ type Listener interface { Name() string // Init is used by the listener to access the core teamserver, needed for: - // - Fetching server-side transport/session-level credentials. - // - Authenticating users connections/requests. - // - Using the builtin teamserver loggers, filesystem and other utilities. + // - Fetching server-side transport/session-level credentials. + // - Authenticating users connections/requests. + // - Using the builtin teamserver loggers, filesystem and other utilities. // Any non-nil error returned will abort the listener starting process. Init(s *Server) error @@ -68,8 +68,8 @@ type Listener interface { // Close should close the listener stack. // This can mean different things depending on use case, but some are not recommended. - // - It can simply close the "listener" layer without shutting down the "server/RPC" layer. - // - It can shutdown anything, thus in effect disconnecting all of its clients from server. + // - It can simply close the "listener" layer without shutting down the "server/RPC" layer. + // - It can shutdown anything, thus in effect disconnecting all of its clients from server. Close() error } diff --git a/server/users.go b/server/users.go index 526dd72..d94ac9d 100644 --- a/server/users.go +++ b/server/users.go @@ -136,9 +136,9 @@ func (ts *Server) UserDelete(name string) error { // user of a connected/connecting teamclient. The token is hashed and checked against the // teamserver users database for the matching user. // This function shall alternatively return: -// - The name of the authenticated user, true for authenticated and no error. -// - No name, false for authenticated, and an ErrUnauthenticated error. -// - No name, false for authenticated, and a database error, if was ignited now. +// - The name of the authenticated user, true for authenticated and no error. +// - No name, false for authenticated, and an ErrUnauthenticated error. +// - No name, false for authenticated, and a database error, if was ignited now. // // This call updates the last time the user has been seen by the server. func (ts *Server) UserAuthenticate(rawToken string) (name string, authorized bool, err error) { From 3b6554d471b160d57bdf993e2131f049472cf2d4 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:23:11 +0200 Subject: [PATCH 23/40] Tidy comments --- example/transports/grpc/client/client.go | 9 +++---- example/transports/grpc/client/middleware.go | 2 +- example/transports/grpc/common/log.go | 2 +- example/transports/grpc/server/middleware.go | 27 ++++++++++++-------- internal/db/sql-cgo.go | 1 - internal/log/cli.go | 22 ++++++++-------- server/config.go | 2 +- server/jobs.go | 4 +-- 8 files changed, 37 insertions(+), 32 deletions(-) diff --git a/example/transports/grpc/client/client.go b/example/transports/grpc/client/client.go index ac66e61..d3cb9bb 100644 --- a/example/transports/grpc/client/client.go +++ b/example/transports/grpc/client/client.go @@ -24,12 +24,11 @@ import ( "fmt" "time" - "google.golang.org/grpc" - "google.golang.org/grpc/status" - "github.com/reeflective/team" "github.com/reeflective/team/client" "github.com/reeflective/team/example/transports/grpc/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/status" ) const ( @@ -163,11 +162,11 @@ func (h *Teamclient) Users() (users []team.User, err error) { return } -// ServerVersion returns the version information of the server to which +// VersionServer returns the version information of the server to which // the client is connected, or nil and an error if it could not retrieve it. // If the gRPC teamclient is not connected or does not have an RPC client, // an ErrNoRPC is returned. -func (h *Teamclient) Version() (version team.Version, err error) { +func (h *Teamclient) VersionServer() (version team.Version, err error) { if h.rpc == nil { return version, ErrNoRPC } diff --git a/example/transports/grpc/client/middleware.go b/example/transports/grpc/client/middleware.go index 45a4a22..01d54ee 100644 --- a/example/transports/grpc/client/middleware.go +++ b/example/transports/grpc/client/middleware.go @@ -86,7 +86,7 @@ func tlsAuthMiddleware(cli *client.Client) ([]grpc.DialOption, error) { }, nil } -// Return value is mapped to request headers. +// GetRequestMetadata return values that are mapped to request headers. func (t TokenAuth) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) { return map[string]string{ "Authorization": "Bearer " + string(t), diff --git a/example/transports/grpc/common/log.go b/example/transports/grpc/common/log.go index 476805c..54a32ff 100644 --- a/example/transports/grpc/common/log.go +++ b/example/transports/grpc/common/log.go @@ -23,7 +23,7 @@ import ( "google.golang.org/grpc/codes" ) -// Maps a grpc response code to a logging level. +// CodeToLevel maps a grpc response code to a logging level. func CodeToLevel(code codes.Code) logrus.Level { switch code { case codes.OK: diff --git a/example/transports/grpc/server/middleware.go b/example/transports/grpc/server/middleware.go index c207bc3..cb9ce5b 100644 --- a/example/transports/grpc/server/middleware.go +++ b/example/transports/grpc/server/middleware.go @@ -49,20 +49,20 @@ func BufferingOptions() (options []grpc.ServerOption) { // preconfigured to perform the following tasks: // - Log all connections/disconnections to/from the teamserver listener. // - Log all raw client requests into a teamserver audit file (see server.AuditLog()). -func LogMiddlewareOptions(s *server.Server) ([]grpc.ServerOption, error) { +func LogMiddlewareOptions(serv *server.Server) ([]grpc.ServerOption, error) { var requestOpts []grpc.UnaryServerInterceptor var streamOpts []grpc.StreamServerInterceptor - cfg := s.GetConfig() + cfg := serv.GetConfig() // Audit-log all requests. Any failure to audit-log the requests // of this server will themselves be logged to the root teamserver log. - auditLog, err := s.AuditLogger() + auditLog, err := serv.AuditLogger() if err != nil { return nil, err } - requestOpts = append(requestOpts, auditLogUnaryServerInterceptor(s, auditLog)) + requestOpts = append(requestOpts, auditLogUnaryServerInterceptor(serv, auditLog)) requestOpts = append(requestOpts, grpc_tags.UnaryServerInterceptor(grpc_tags.WithFieldExtractor(grpc_tags.CodeGenRequestFieldExtractor)), @@ -73,7 +73,7 @@ func LogMiddlewareOptions(s *server.Server) ([]grpc.ServerOption, error) { ) // Logging interceptors - logrusEntry := s.NamedLogger("transport", "grpc") + logrusEntry := serv.NamedLogger("transport", "grpc") logrusOpts := []grpc_logrus.Option{ grpc_logrus.WithLevels(common.CodeToLevel), } @@ -150,10 +150,17 @@ func (ts *Teamserver) initAuthMiddleware() ([]grpc.ServerOption, error) { }, nil } -// TODO: Should we change the default in-memory server name ? +// ContextKey represents a gRPC context metadata key. +type ContextKey int + +const ( + Transport ContextKey = iota + User +) + func serverAuthFunc(ctx context.Context) (context.Context, error) { - newCtx := context.WithValue(ctx, "transport", "local") - newCtx = context.WithValue(newCtx, "user", "server") + newCtx := context.WithValue(ctx, Transport, "local") + newCtx = context.WithValue(newCtx, User, "server") return newCtx, nil } @@ -174,8 +181,8 @@ func (ts *Teamserver) tokenAuthFunc(ctx context.Context) (context.Context, error return nil, status.Error(codes.Unauthenticated, "Authentication failure") } - newCtx := context.WithValue(ctx, "transport", "mtls") - newCtx = context.WithValue(newCtx, "user", user) + newCtx := context.WithValue(ctx, Transport, "mtls") + newCtx = context.WithValue(newCtx, User, user) return newCtx, nil } diff --git a/internal/db/sql-cgo.go b/internal/db/sql-cgo.go index 5dd5b81..d35f0c9 100644 --- a/internal/db/sql-cgo.go +++ b/internal/db/sql-cgo.go @@ -23,7 +23,6 @@ package db import ( _ "github.com/ncruces/go-sqlite3/embed" - _ "github.com/mattn/go-sqlite3" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" diff --git a/internal/log/cli.go b/internal/log/cli.go index 98aaf6a..969d9f8 100644 --- a/internal/log/cli.go +++ b/internal/log/cli.go @@ -37,13 +37,13 @@ const ( ) const ( - FieldTimestamp = "timestamp" - FieldPackage = "logger" - FieldMessage = "message" + fieldTimestamp = "timestamp" + fieldPackage = "logger" + fieldMessage = "message" PackageFieldKey = "teamserver_pkg" - MinimumPackagePad = 11 + minimumPackagePad = 11 ) // stdioHook combines a stdout hook (info/debug/trace), @@ -152,15 +152,15 @@ func (hook *stdoutHook) Format(entry *logrus.Entry) ([]byte, error) { levelLog := fmt.Sprintf("%s%s%s", color(signColor), sign, color(style.Default)) timestamp := entry.Time.Format(hook.TimestampFormat) - timestampLog := fmt.Sprintf("%s%s%s", color(hook.Colors[FieldTimestamp]), timestamp, color(style.Default)) + timestampLog := fmt.Sprintf("%s%s%s", color(hook.Colors[fieldTimestamp]), timestamp, color(style.Default)) var pkgLogF string pkg := entry.Data[PackageFieldKey] if pkg != nil { pkgLog := fmt.Sprintf(" %v ", pkg) - pkgLog = fmt.Sprintf("%-*s", MinimumPackagePad, pkgLog) - pkgLogF = strings.ReplaceAll(pkgLog, fmt.Sprintf("%s", pkg), fmt.Sprintf("%s%s%s", color(hook.Colors[FieldPackage]), pkg, color(style.Default))) + pkgLog = fmt.Sprintf("%-*s", minimumPackagePad, pkgLog) + pkgLogF = strings.ReplaceAll(pkgLog, fmt.Sprintf("%s", pkg), fmt.Sprintf("%s%s%s", color(hook.Colors[fieldPackage]), pkg, color(style.Default))) } // Always try to unwrap the error at least once, and colorize it. @@ -171,7 +171,7 @@ func (hook *stdoutHook) Format(entry *logrus.Entry) ([]byte, error) { } } - messageLog := fmt.Sprintf("%s%s%s", color(hook.Colors[FieldMessage]), message, color(style.Default)) + messageLog := fmt.Sprintf("%s%s%s", color(hook.Colors[fieldMessage]), message, color(style.Default)) // Assemble the log message var logMessage string @@ -265,9 +265,9 @@ func (hook *stderrHook) Levels() []logrus.Level { func defaultFieldsFormat() map[string]string { return map[string]string{ - FieldTimestamp: style.BrightBlack, - FieldPackage: style.Dim, - FieldMessage: style.BrightWhite, + fieldTimestamp: style.BrightBlack, + fieldPackage: style.Dim, + fieldMessage: style.BrightWhite, } } diff --git a/server/config.go b/server/config.go index 25dfb24..68036e6 100644 --- a/server/config.go +++ b/server/config.go @@ -135,7 +135,7 @@ func (ts *Server) GetConfig() *Config { return ts.opts.config } -// Save saves config file to disk. +// SaveConfig saves config file to disk. // This uses the on-disk filesystem even if the teamclient is in memory mode. func (ts *Server) SaveConfig(cfg *Config) error { cfgLog := ts.NamedLogger("config", "server") diff --git a/server/jobs.go b/server/jobs.go index 3841dec..c2004fe 100644 --- a/server/jobs.go +++ b/server/jobs.go @@ -79,7 +79,7 @@ func (ts *Server) Listeners() []*job { return all } -// AddListenerJob adds a teamserver listener job to the teamserver configuration. +// ListenerAdd adds a teamserver listener job to the teamserver configuration. // This function does not start the given listener, and you must call the server // ServeAddr(name, host, port) function for this. func (ts *Server) ListenerAdd(name, host string, port uint16) error { @@ -104,7 +104,7 @@ func (ts *Server) ListenerAdd(name, host string, port uint16) error { return ts.SaveConfig(ts.opts.config) } -// RemoveListenerJob removes a server listener job from the configuration. +// ListenerRemove removes a server listener job from the configuration. // This function does not stop any running listener for the given ID: you // must call server.CloseListener(id) for this. func (ts *Server) ListenerRemove(listenerID string) { From 7fd7c8bef484ad7df7238ce6abccdbcaef22e84f Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:46:16 +0200 Subject: [PATCH 24/40] Cleanup and comments tidying --- client/config.go | 2 +- client/directories.go | 10 +++++----- internal/assets/fs.go | 9 ++++++--- internal/certs/ca.go | 4 ++-- internal/certs/certs.go | 2 +- internal/certs/tls.go | 4 +++- internal/command/command.go | 22 ++++++++++++++-------- internal/db/sql-cgo.go | 3 +++ internal/db/sql-go.go | 1 + internal/db/sql-wasm.go | 3 +++ internal/db/sql.go | 2 ++ internal/log/cli.go | 10 +++++----- internal/log/log.go | 19 +++++++------------ internal/log/perms.go | 2 +- internal/systemd/config.go | 2 ++ internal/version/.gitignore | 1 - internal/version/teamserver_version_info | 14 -------------- internal/version/version.go | 2 +- server/commands/user.go | 8 ++++---- server/config.go | 7 ++++--- server/db.go | 4 ++-- server/directories.go | 8 ++++---- 22 files changed, 71 insertions(+), 68 deletions(-) delete mode 100644 internal/version/.gitignore delete mode 100644 internal/version/teamserver_version_info diff --git a/client/config.go b/client/config.go index e4eafee..f389cb9 100644 --- a/client/config.go +++ b/client/config.go @@ -154,7 +154,7 @@ func (tc *Client) SaveConfig(config *Config) error { // If we are in-memory, still make the directory. if _, err := os.Stat(configDir); os.IsNotExist(err) { - if err = os.MkdirAll(configDir, log.DirPerm); err != nil { + if err = os.MkdirAll(configDir, assets.DirPerm); err != nil { return tc.errorf("%w: %w", ErrConfig, err) } } diff --git a/client/directories.go b/client/directories.go index 96430bf..f969f3b 100644 --- a/client/directories.go +++ b/client/directories.go @@ -45,7 +45,7 @@ func (tc *Client) HomeDir() string { dir = "." + tc.name } - err := tc.fs.MkdirAll(dir, log.DirPerm) + err := tc.fs.MkdirAll(dir, assets.DirPerm) if err != nil { tc.log().Errorf("cannot write to %s root dir: %s", dir, err) } @@ -59,7 +59,7 @@ func (tc *Client) HomeDir() string { func (tc *Client) TeamDir() string { dir := filepath.Join(tc.HomeDir(), tc.opts.teamDir) - err := tc.fs.MkdirAll(dir, log.DirPerm) + err := tc.fs.MkdirAll(dir, assets.DirPerm) if err != nil { tc.log().Errorf("cannot write to %s root dir: %s", dir, err) } @@ -72,7 +72,7 @@ func (tc *Client) TeamDir() string { func (tc *Client) LogsDir() string { logsDir := filepath.Join(tc.TeamDir(), assets.DirLogs) - err := tc.fs.MkdirAll(logsDir, log.DirPerm) + err := tc.fs.MkdirAll(logsDir, assets.DirPerm) if err != nil { tc.log().Errorf("cannot write to %s root dir: %s", logsDir, err) } @@ -80,14 +80,14 @@ func (tc *Client) LogsDir() string { return logsDir } -// GetConfigDir returns the path to the remote teamserver configs directory +// ConfigsDir returns the path to the remote teamserver configs directory // for this application (~/.app/teamclient/configs), creating the directory // if needed, or logging a fatal event if failing to create it. func (tc *Client) ConfigsDir() string { rootDir, _ := filepath.Abs(tc.TeamDir()) dir := filepath.Join(rootDir, assets.DirConfigs) - err := tc.fs.MkdirAll(dir, log.DirPerm) + err := tc.fs.MkdirAll(dir, assets.DirPerm) if err != nil { tc.log().Errorf("cannot write to %s configs dir: %s", dir, err) } diff --git a/internal/assets/fs.go b/internal/assets/fs.go index d70442b..1846199 100644 --- a/internal/assets/fs.go +++ b/internal/assets/fs.go @@ -28,9 +28,12 @@ import ( ) const ( - FileReadPerm = 0o600 // FileReadPerm is the permission bit given to the OS when reading files. - DirPerm = 0o700 // DirPerm is the permission bit given to teamserver/client directories. - FileWritePerm = 0o644 // FileWritePerm is the permission bit given to the OS when writing files. + // FileReadPerm is the permission bit given to the OS when reading files. + FileReadPerm = 0o600 + // DirPerm is the permission bit given to teamserver/client directories. + DirPerm = 0o700 + // FileWritePerm is the permission bit given to the OS when writing files. + FileWritePerm = 0o644 // FileWriteOpenMode is used when opening log files in append/create/write-only mode. FileWriteOpenMode = os.O_APPEND | os.O_CREATE | os.O_WRONLY diff --git a/internal/certs/ca.go b/internal/certs/ca.go index 6550626..5255131 100644 --- a/internal/certs/ca.go +++ b/internal/certs/ca.go @@ -137,12 +137,12 @@ func (c *Manager) saveCA(caType string, cert []byte, key []byte) { certFilePath := filepath.Join(storageDir, fmt.Sprintf("%s_%s-ca-cert.%s", c.appName, caType, certFileExt)) keyFilePath := filepath.Join(storageDir, fmt.Sprintf("%s_%s-ca-key.%s", c.appName, caType, certFileExt)) - err := c.fs.WriteFile(certFilePath, cert, log.FileReadPerm) + err := c.fs.WriteFile(certFilePath, cert, assets.FileReadPerm) if err != nil { c.log.Fatalf("Failed write certificate data to %s, %s", certFilePath, err) } - err = c.fs.WriteFile(keyFilePath, key, log.FileReadPerm) + err = c.fs.WriteFile(keyFilePath, key, assets.FileReadPerm) if err != nil { c.log.Fatalf("Failed write certificate data to %s: %s", keyFilePath, err) } diff --git a/internal/certs/certs.go b/internal/certs/certs.go index 5af5a01..83dcf98 100644 --- a/internal/certs/certs.go +++ b/internal/certs/certs.go @@ -317,7 +317,7 @@ func (c *Manager) getCertDir() string { rootDir := c.appDir certDir := filepath.Join(rootDir, "certs") - err := c.fs.MkdirAll(certDir, log.DirPerm) + err := c.fs.MkdirAll(certDir, assets.DirPerm) if err != nil { c.log.Fatalf("Failed to create cert dir: %s", err) } diff --git a/internal/certs/tls.go b/internal/certs/tls.go index eb403be..a9a19f6 100644 --- a/internal/certs/tls.go +++ b/internal/certs/tls.go @@ -24,10 +24,12 @@ import ( "log" "os" + "github.com/reeflective/team/internal/assets" teamlog "github.com/reeflective/team/internal/log" ) const ( + // DefaultPort is the default team.Server listening port. // Should be 31415, but... go to hell with your endless limits. DefaultPort = 31416 ) @@ -37,7 +39,7 @@ const ( func (c *Manager) OpenTLSKeyLogFile() *os.File { keyFilePath, present := os.LookupEnv("SSLKEYLOGFILE") if present { - keyFile, err := os.OpenFile(keyFilePath, teamlog.FileWriteOpenMode, teamlog.FileReadPerm) + keyFile, err := os.OpenFile(keyFilePath, assets.FileWriteOpenMode, assets.FileReadPerm) if err != nil { c.log.Errorf("Failed to open TLS key file %v", err) return nil diff --git a/internal/command/command.go b/internal/command/command.go index e763f8b..9718ae7 100644 --- a/internal/command/command.go +++ b/internal/command/command.go @@ -25,18 +25,24 @@ import ( ) type ( + // CobraRunnerE is a cobra runner returning an error. CobraRunnerE func(*cobra.Command, []string) error - CobraRunner func(*cobra.Command, []string) + // CobraRunner is a cobra runner returning nothing. + CobraRunner func(*cobra.Command, []string) ) const ( - ClientConfigExt = "teamclient.cfg" // Client remote server config file extension. - ServerConfigExt = "teamserver.json" // Server backend config file extension. + // ClientConfigExt is the client remote server config file extension. + ClientConfigExt = "teamclient.cfg" + // ServerConfigExt is the server backend config file extension. + ServerConfigExt = "teamserver.json" ) const ( - TeamServerGroup = "teamserver control" // TeamServerGroup is the group of all server/client control commands. - UserManagementGroup = "user management" // UserManagementGroup is the group to manage teamserver users. + // TeamServerGroup is the group of all server/client control commands. + TeamServerGroup = "teamserver control" + // UserManagementGroup is the group to manage teamserver users. + UserManagementGroup = "user management" ) // Colors / effects. @@ -57,11 +63,11 @@ const ( DownN = "\033[%dB" Underline = "\033[4m" - // info - Display colorful information. + // Info - Display colorful information. Info = Cyan + "[*] " + Normal - // warn - warn a user. + // Warn - warn a user. Warn = Red + "[!] " + Normal - // debugl - Display debugl information. + // Debugl - Display debugl information. Debugl = Purple + "[-] " + Normal ) diff --git a/internal/db/sql-cgo.go b/internal/db/sql-cgo.go index d35f0c9..f329800 100644 --- a/internal/db/sql-cgo.go +++ b/internal/db/sql-cgo.go @@ -21,7 +21,10 @@ package db */ import ( + // Embedded SQLite instance. _ "github.com/ncruces/go-sqlite3/embed" + // C-code. + _ "github.com/ncruces/go-sqlite3" "gorm.io/driver/sqlite" "gorm.io/gorm" diff --git a/internal/db/sql-go.go b/internal/db/sql-go.go index 7173c6d..302aa0f 100644 --- a/internal/db/sql-go.go +++ b/internal/db/sql-go.go @@ -21,6 +21,7 @@ package db */ import ( + // Embed the sqlite code into our teamserver. _ "github.com/ncruces/go-sqlite3/embed" "github.com/ncruces/go-sqlite3/gormlite" "gorm.io/gorm" diff --git a/internal/db/sql-wasm.go b/internal/db/sql-wasm.go index 558d642..213b48d 100644 --- a/internal/db/sql-wasm.go +++ b/internal/db/sql-wasm.go @@ -21,8 +21,11 @@ package db */ import ( + // Core code. _ "github.com/ncruces/go-sqlite3" + // Driver code. _ "github.com/ncruces/go-sqlite3/driver" + // Embedded SQLite instance. _ "github.com/ncruces/go-sqlite3/embed" "gorm.io/gorm" "gorm.io/gorm/logger" diff --git a/internal/db/sql.go b/internal/db/sql.go index 00a030b..f49e428 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -32,6 +32,8 @@ import ( ) const ( + // SQLiteInMemoryHost is the default string used by SQLite + // as a host when ran in memory (string value is ":memory:"). SQLiteInMemoryHost = ":memory:" ) diff --git a/internal/log/cli.go b/internal/log/cli.go index 969d9f8..302d47d 100644 --- a/internal/log/cli.go +++ b/internal/log/cli.go @@ -30,10 +30,10 @@ import ( // Text effects. const ( - SGRStart = "\x1b[" - Fg = "38;05;" - Bg = "48;05;" - SGREnd = "m" + sgrStart = "\x1b[" + fg = "38;05;" + bg = "48;05;" + sgrEnd = "m" ) const ( @@ -296,5 +296,5 @@ func defaultLevelFieldsColored() map[string]string { } func color(color string) string { - return SGRStart + style.SGR(color) + SGREnd + return sgrStart + style.SGR(color) + sgrEnd } diff --git a/internal/log/log.go b/internal/log/log.go index fdf5f1a..b31cccf 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -21,7 +21,6 @@ package log import ( "fmt" "io" - "os" "path/filepath" "github.com/reeflective/team/internal/assets" @@ -29,21 +28,17 @@ import ( ) const ( - FileReadPerm = 0o600 // FileReadPerm is the permission bit given to the OS when reading files. - DirPerm = 0o700 // DirPerm is the permission bit given to teamserver/client directories. - FileWritePerm = 0o644 // FileWritePerm is the permission bit given to the OS when writing files. - - FileWriteOpenMode = os.O_APPEND | os.O_CREATE | os.O_WRONLY // Opening log files in append/create/write-only mode. - - ClientLogFileExt = "teamclient.log" // Log files of all teamclients have this extension by default. - ServerLogFileExt = "teamserver.log" // Log files of all teamserver have this extension by default. + // ClientLogFileExt is used as extension by all main teamclients log files by default. + ClientLogFileExt = "teamclient.log" + // ServerLogFileExt is used as extension by all teamservers core log files by default. + ServerLogFileExt = "teamserver.log" ) // Init is the main constructor that is (and should be) used for teamserver and teamclient logging. // It hooks a normal logger with a sublogger writing to a file in text version, and another logger // writing to stdout/stderr with enhanced formatting/coloring support. func Init(fs *assets.FS, file string, level logrus.Level) (*logrus.Logger, *logrus.Logger, error) { - logFile, err := fs.OpenFile(file, FileWriteOpenMode, FileWritePerm) + logFile, err := fs.OpenFile(file, assets.FileWriteOpenMode, assets.FileWritePerm) if err != nil { return nil, nil, fmt.Errorf("Failed to open log file %w", err) } @@ -102,7 +97,7 @@ func NewJSON(fs *assets.FS, file string, level logrus.Level) (*logrus.Logger, er rootLogger.Formatter = &logrus.JSONFormatter{} jsonFilePath := fmt.Sprintf("%s.json", file) - logFile, err := fs.OpenFile(jsonFilePath, FileWriteOpenMode, FileWritePerm) + logFile, err := fs.OpenFile(jsonFilePath, assets.FileWriteOpenMode, assets.FileWritePerm) if err != nil { return nil, fmt.Errorf("Failed to open log file %w", err) } @@ -121,7 +116,7 @@ func NewAudit(fs *assets.FS, logDir string) (*logrus.Logger, error) { auditLogger.Formatter = &logrus.JSONFormatter{} jsonFilePath := filepath.Join(logDir, "audit.json") - logFile, err := fs.OpenFile(jsonFilePath, FileWriteOpenMode, FileWritePerm) + logFile, err := fs.OpenFile(jsonFilePath, assets.FileWriteOpenMode, assets.FileWritePerm) if err != nil { return nil, fmt.Errorf("Failed to open log file %w", err) } diff --git a/internal/log/perms.go b/internal/log/perms.go index b56f909..2eea129 100644 --- a/internal/log/perms.go +++ b/internal/log/perms.go @@ -35,7 +35,6 @@ func IsWritable(path string) (isWritable bool, err error) { return } - err = nil if !info.IsDir() { return false, fmt.Errorf("Path isn't a directory") } @@ -56,5 +55,6 @@ func IsWritable(path string) (isWritable bool, err error) { } isWritable = true + return } diff --git a/internal/systemd/config.go b/internal/systemd/config.go index 705acf0..585f6e3 100644 --- a/internal/systemd/config.go +++ b/internal/systemd/config.go @@ -20,6 +20,7 @@ package systemd import ( "bytes" + // Embed our example teamserver.service file. _ "embed" "fmt" "log" @@ -41,6 +42,7 @@ type Config struct { //go:embed teamserver.service var systemdServiceTemplate string +// NewFrom returns a new templated systemd configuration file. func NewFrom(name string, userCfg *Config) string { cfg := NewDefaultConfig() diff --git a/internal/version/.gitignore b/internal/version/.gitignore deleted file mode 100644 index 1d65b47..0000000 --- a/internal/version/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.compiled diff --git a/internal/version/teamserver_version_info b/internal/version/teamserver_version_info deleted file mode 100644 index 25a898d..0000000 --- a/internal/version/teamserver_version_info +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -outfile="_version.compiled" - -git describe --abbrev=0 --always > "client${outfile}" -go version > "go${outfile}" -git rev-parse HEAD > "commit${outfile}" - -# Dirty (ensure file exists for github actions) -touch "dirty${outfile}" -git diff --quiet || echo 'Dirty' > "dirty${outfile}" - -# Compilation time -date +%s > "compiled${outfile}" diff --git a/internal/version/version.go b/internal/version/version.go index 113acd9..a6a83ae 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -19,7 +19,6 @@ package version */ import ( - _ "embed" "errors" "runtime/debug" "strconv" @@ -31,6 +30,7 @@ const ( semVerLen = 3 ) +// ErrNoBuildInfo is an error indicating that we could not fetch any binary build info. var ErrNoBuildInfo = errors.New("No binary build info") // Semantic - Get the structured semantic diff --git a/server/commands/user.go b/server/commands/user.go index 07eae72..821d656 100644 --- a/server/commands/user.go +++ b/server/commands/user.go @@ -3,13 +3,13 @@ package commands import ( "encoding/json" "fmt" - "io/ioutil" "os" "os/user" "path/filepath" "strings" "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/log" "github.com/reeflective/team/server" @@ -50,7 +50,7 @@ func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Comm filename = fmt.Sprintf("%s_%s_default", serv.Name(), user.Username) saveTo = cli.ConfigsDir() - err = os.MkdirAll(saveTo, log.DirPerm) + err = os.MkdirAll(saveTo, assets.DirPerm) if err != nil { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"cannot write to %s root dir: %s\n", saveTo, err) return @@ -84,7 +84,7 @@ func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Comm saveTo = filepath.Join(saveTo, filename+".teamclient.cfg") - err = ioutil.WriteFile(saveTo, configJSON, log.FileReadPerm) + err = os.WriteFile(saveTo, configJSON, assets.FileReadPerm) if err != nil { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Failed to write config to %s: %s\n", saveTo, err) return @@ -207,7 +207,7 @@ func exportCACmd(serv *server.Server) func(cmd *cobra.Command, args []string) { data, _ := json.Marshal(exportedCA) - err = os.WriteFile(saveTo, data, log.FileWritePerm) + err = os.WriteFile(saveTo, data, assets.FileWritePerm) if err != nil { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Write failed: %s (%s)\n", saveTo, err) return diff --git a/server/config.go b/server/config.go index 68036e6..5755247 100644 --- a/server/config.go +++ b/server/config.go @@ -27,6 +27,7 @@ import ( "path/filepath" "time" + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" @@ -80,7 +81,7 @@ func (ts *Server) ConfigPath() string { appDir := ts.TeamDir() configDir := filepath.Join(appDir, "configs") - err := ts.fs.MkdirAll(configDir, log.DirPerm) + err := ts.fs.MkdirAll(configDir, assets.DirPerm) if err != nil { ts.log().Errorf("cannot write to %s config dir: %s", configDir, err) } @@ -150,7 +151,7 @@ func (ts *Server) SaveConfig(cfg *Config) error { if _, err := os.Stat(configDir); os.IsNotExist(err) { cfgLog.Debugf("Creating config dir %s", configDir) - err := os.MkdirAll(configDir, log.DirPerm) + err := os.MkdirAll(configDir, assets.DirPerm) if err != nil { return ts.errorf("%w: %w", ErrConfig, err) } @@ -163,7 +164,7 @@ func (ts *Server) SaveConfig(cfg *Config) error { cfgLog.Debugf("Saving config to %s", configPath) - err = os.WriteFile(configPath, data, log.FileReadPerm) + err = os.WriteFile(configPath, data, assets.FileReadPerm) if err != nil { return ts.errorf("%w: failed to write config: %s", ErrConfig, err) } diff --git a/server/db.go b/server/db.go index 9ecafe4..a3c16be 100644 --- a/server/db.go +++ b/server/db.go @@ -85,7 +85,7 @@ func (ts *Server) saveDatabaseConfig(cfg *db.Config) error { if _, err := os.Stat(configDir); os.IsNotExist(err) { dblog.Debugf("Creating config dir %s", configDir) - err := os.MkdirAll(configDir, log.DirPerm) + err := os.MkdirAll(configDir, assets.DirPerm) if err != nil { return err } @@ -98,7 +98,7 @@ func (ts *Server) saveDatabaseConfig(cfg *db.Config) error { dblog.Debugf("Saving config to %s", configPath) - return os.WriteFile(configPath, data, log.FileReadPerm) + return os.WriteFile(configPath, data, assets.FileReadPerm) } // getDatabaseConfig returns a working database configuration, diff --git a/server/directories.go b/server/directories.go index 4c96c2a..044ca96 100644 --- a/server/directories.go +++ b/server/directories.go @@ -46,7 +46,7 @@ func (ts *Server) HomeDir() string { dir = "." + ts.name } - err := ts.fs.MkdirAll(dir, log.DirPerm) + err := ts.fs.MkdirAll(dir, assets.DirPerm) if err != nil { ts.log().Errorf("cannot write to %s root dir: %s", dir, err) } @@ -60,7 +60,7 @@ func (ts *Server) HomeDir() string { func (ts *Server) TeamDir() string { dir := path.Join(ts.HomeDir(), ts.opts.teamDir) - err := ts.fs.MkdirAll(dir, log.DirPerm) + err := ts.fs.MkdirAll(dir, assets.DirPerm) if err != nil { ts.log().Errorf("cannot write to %s root dir: %s", dir, err) } @@ -73,7 +73,7 @@ func (ts *Server) TeamDir() string { func (ts *Server) LogsDir() string { logDir := path.Join(ts.TeamDir(), assets.DirLogs) - err := ts.fs.MkdirAll(logDir, log.DirPerm) + err := ts.fs.MkdirAll(logDir, assets.DirPerm) if err != nil { ts.log().Errorf("cannot write to %s root dir: %s", logDir, err) } @@ -86,7 +86,7 @@ func (ts *Server) LogsDir() string { func (ts *Server) CertificatesDir() string { certDir := path.Join(ts.TeamDir(), assets.DirCerts) - err := ts.fs.MkdirAll(certDir, log.DirPerm) + err := ts.fs.MkdirAll(certDir, assets.DirPerm) if err != nil { ts.log().Errorf("cannot write to %s root dir: %s", certDir, err) } From 1840d40300ea86b9308b90b0a42ba53ccfafe16e Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:48:39 +0200 Subject: [PATCH 25/40] Fix actions --- .github/workflows/go.yml | 4 ---- internal/assets/fs.go | 15 ++++++++++----- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4e7fe66..45db49f 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -25,10 +25,6 @@ jobs: with: go-version: 1.21 - - name: Version information - run: bash teamserver_version_info - working-directory: internal/version - - name: Teamclient example working-directory: example/teamclient run: go build -v . diff --git a/internal/assets/fs.go b/internal/assets/fs.go index 1846199..8fec1db 100644 --- a/internal/assets/fs.go +++ b/internal/assets/fs.go @@ -42,14 +42,19 @@ const ( const ( // Teamclient. - DirClient = "teamclient" // DirClient is the name of the teamclient subdirectory. - DirLogs = "logs" // DirLogs subdirectory name - DirConfigs = "configs" // DirConfigs subdirectory name + // DirClient is the name of the teamclient subdirectory. + DirClient = "teamclient" + // DirLogs subdirectory name. + DirLogs = "logs" + // DirConfigs subdirectory name. + DirConfigs = "configs" // Teamserver. - DirServer = "teamserver" // DirClient is the name of the teamserver subdirectory. - DirCerts = "certs" // DirCerts subdirectory name + // DirServer is the name of the teamserver subdirectory. + DirServer = "teamserver" + // DirCerts subdirectory name. + DirCerts = "certs" ) // FS is a filesystem abstraction for teamservers and teamclients. From 14dde504b3655eaf7727128927176a853f665bb7 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:52:14 +0200 Subject: [PATCH 26/40] Remove logging of cleartext credentials --- internal/db/sql.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/db/sql.go b/internal/db/sql.go index f49e428..b8f86d3 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -56,10 +56,11 @@ func NewClient(dbConfig *Config, dbLogger *logrus.Entry) (*gorm.DB, error) { // Logging middleware (queries) dbLog := log.NewDatabase(dbLogger, dbConfig.LogLevel) + logDbDsn := fmt.Sprintf("%s (%s:%d)", dbConfig.Database, dbConfig.Host, dbConfig.Port) switch dbConfig.Dialect { case Sqlite: - dbLogger.Infof("Connecting to SQLite database %s", dsn) + dbLogger.Infof("Connecting to SQLite database %s", logDbDsn) dbClient, err = sqliteClient(dsn, dbLog) if err != nil { @@ -67,7 +68,7 @@ func NewClient(dbConfig *Config, dbLogger *logrus.Entry) (*gorm.DB, error) { } case Postgres: - dbLogger.Infof("Connecting to PostgreSQL database %s", dsn) + dbLogger.Infof("Connecting to PostgreSQL database %s", logDbDsn) dbClient, err = postgresClient(dsn, dbLog) if err != nil { @@ -75,7 +76,7 @@ func NewClient(dbConfig *Config, dbLogger *logrus.Entry) (*gorm.DB, error) { } case MySQL: - dbLogger.Infof("Connecting to MySQL database %s", dsn) + dbLogger.Infof("Connecting to MySQL database %s", logDbDsn) dbClient, err = mySQLClient(dsn, dbLog) if err != nil { From be74c028b12b9ef4665e75e11bdbaf125471663f Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:55:06 +0200 Subject: [PATCH 27/40] Fix imports --- internal/certs/ca.go | 2 +- internal/certs/certs.go | 1 - internal/certs/tls.go | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/certs/ca.go b/internal/certs/ca.go index 5255131..7a00738 100644 --- a/internal/certs/ca.go +++ b/internal/certs/ca.go @@ -26,7 +26,7 @@ import ( "os" "path/filepath" - "github.com/reeflective/team/internal/log" + "github.com/reeflective/team/internal/assets" ) // ----------------------- diff --git a/internal/certs/certs.go b/internal/certs/certs.go index 83dcf98..f6bca0a 100644 --- a/internal/certs/certs.go +++ b/internal/certs/certs.go @@ -38,7 +38,6 @@ import ( "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/db" - "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" "gorm.io/gorm" ) diff --git a/internal/certs/tls.go b/internal/certs/tls.go index a9a19f6..9064745 100644 --- a/internal/certs/tls.go +++ b/internal/certs/tls.go @@ -25,7 +25,6 @@ import ( "os" "github.com/reeflective/team/internal/assets" - teamlog "github.com/reeflective/team/internal/log" ) const ( From 2aac56ae45a41c43d7af74e0cf1dfc9f59f9221b Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:57:40 +0200 Subject: [PATCH 28/40] Fix client imports --- client/config.go | 2 +- client/directories.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/client/config.go b/client/config.go index f389cb9..ee616aa 100644 --- a/client/config.go +++ b/client/config.go @@ -29,9 +29,9 @@ import ( "path/filepath" "sort" + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/command" - "github.com/reeflective/team/internal/log" "gopkg.in/AlecAivazis/survey.v1" ) diff --git a/client/directories.go b/client/directories.go index f969f3b..8833282 100644 --- a/client/directories.go +++ b/client/directories.go @@ -23,7 +23,6 @@ import ( "path/filepath" "github.com/reeflective/team/internal/assets" - "github.com/reeflective/team/internal/log" ) // HomeDir returns the root application directory (~/.app/ by default). From de56f43fff3fbd8e0fc569bf31bea74a8f0c6aab Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 19:58:56 +0200 Subject: [PATCH 29/40] Fix and restructure imports --- client/client.go | 3 ++- client/commands/commands.go | 5 +++-- client/commands/import.go | 5 +++-- client/commands/users.go | 5 +++-- client/commands/version.go | 5 +++-- client/config.go | 3 ++- client/log.go | 3 ++- client/options.go | 3 ++- example/teamserver/main.go | 3 ++- example/transports/grpc/client/client.go | 5 +++-- example/transports/grpc/client/middleware.go | 5 +++-- example/transports/grpc/proto/client.pb.go | 5 +++-- example/transports/grpc/proto/service.pb.go | 3 ++- example/transports/grpc/proto/service_grpc.pb.go | 1 + example/transports/grpc/server/middleware.go | 5 +++-- example/transports/grpc/server/server.go | 7 ++++--- internal/certs/certs.go | 5 +++-- internal/db/sql-cgo.go | 4 ++-- internal/db/sql.go | 3 ++- internal/log/log.go | 3 ++- server/commands/commands.go | 7 ++++--- server/commands/completers.go | 3 ++- server/commands/teamserver.go | 5 +++-- server/commands/user.go | 6 +++--- server/config.go | 4 ++-- server/core.go | 5 +++-- server/db.go | 5 +++-- server/directories.go | 1 - server/log.go | 3 ++- server/options.go | 5 +++-- 30 files changed, 75 insertions(+), 50 deletions(-) diff --git a/client/client.go b/client/client.go index 44be641..5669896 100644 --- a/client/client.go +++ b/client/client.go @@ -24,10 +24,11 @@ import ( "runtime" "sync" + "github.com/sirupsen/logrus" + "github.com/reeflective/team" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/version" - "github.com/sirupsen/logrus" ) // Client is the core driver of an application teamclient. diff --git a/client/commands/commands.go b/client/commands/commands.go index 9f714bd..21923a2 100644 --- a/client/commands/commands.go +++ b/client/commands/commands.go @@ -25,12 +25,13 @@ import ( "path/filepath" "strings" - "github.com/reeflective/team/client" - "github.com/reeflective/team/internal/command" "github.com/rsteube/carapace" "github.com/rsteube/carapace/pkg/style" "github.com/spf13/cobra" "github.com/spf13/pflag" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" ) // Generate returns a command tree to embed in client applications connecting diff --git a/client/commands/import.go b/client/commands/import.go index 166a86c..ff470c2 100644 --- a/client/commands/import.go +++ b/client/commands/import.go @@ -22,10 +22,11 @@ import ( "encoding/json" "fmt" - "github.com/reeflective/team/client" - "github.com/reeflective/team/internal/command" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" ) func importCmd(cli *client.Client) func(cmd *cobra.Command, args []string) { diff --git a/client/commands/users.go b/client/commands/users.go index f3045c9..3b7f1ca 100644 --- a/client/commands/users.go +++ b/client/commands/users.go @@ -23,10 +23,11 @@ import ( "time" "github.com/jedib0t/go-pretty/v6/table" - "github.com/reeflective/team/client" - "github.com/reeflective/team/internal/command" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" ) func usersCmd(cli *client.Client) func(cmd *cobra.Command, args []string) error { diff --git a/client/commands/version.go b/client/commands/version.go index 975c0d9..2920bca 100644 --- a/client/commands/version.go +++ b/client/commands/version.go @@ -22,10 +22,11 @@ import ( "fmt" "time" - "github.com/reeflective/team/client" - "github.com/reeflective/team/internal/command" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" ) func versionCmd(cli *client.Client) func(cmd *cobra.Command, args []string) error { diff --git a/client/config.go b/client/config.go index ee616aa..a7a8023 100644 --- a/client/config.go +++ b/client/config.go @@ -29,10 +29,11 @@ import ( "path/filepath" "sort" + "gopkg.in/AlecAivazis/survey.v1" + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/command" - "gopkg.in/AlecAivazis/survey.v1" ) const ( diff --git a/client/log.go b/client/log.go index ed602c2..b4e9a36 100644 --- a/client/log.go +++ b/client/log.go @@ -23,8 +23,9 @@ import ( "io" "path/filepath" - "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" + + "github.com/reeflective/team/internal/log" ) // NamedLogger returns a new logging "thread" with two fields (optional) diff --git a/client/options.go b/client/options.go index 864ca35..bddf81a 100644 --- a/client/options.go +++ b/client/options.go @@ -24,8 +24,9 @@ import ( "os" "strings" - "github.com/reeflective/team/internal/assets" "github.com/sirupsen/logrus" + + "github.com/reeflective/team/internal/assets" ) const noTeamdir = "no team subdirectory" diff --git a/example/teamserver/main.go b/example/teamserver/main.go index ca67e22..61803af 100644 --- a/example/teamserver/main.go +++ b/example/teamserver/main.go @@ -3,11 +3,12 @@ package main import ( "log" + "github.com/rsteube/carapace" + "github.com/reeflective/team/client" grpc "github.com/reeflective/team/example/transports/grpc/server" "github.com/reeflective/team/server" "github.com/reeflective/team/server/commands" - "github.com/rsteube/carapace" ) // main shows how to use a teamserver and teamclient with gRPC backends (transport & RPC). diff --git a/example/transports/grpc/client/client.go b/example/transports/grpc/client/client.go index d3cb9bb..5b1933f 100644 --- a/example/transports/grpc/client/client.go +++ b/example/transports/grpc/client/client.go @@ -24,11 +24,12 @@ import ( "fmt" "time" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + "github.com/reeflective/team" "github.com/reeflective/team/client" "github.com/reeflective/team/example/transports/grpc/proto" - "google.golang.org/grpc" - "google.golang.org/grpc/status" ) const ( diff --git a/example/transports/grpc/client/middleware.go b/example/transports/grpc/client/middleware.go index 01d54ee..bc435ac 100644 --- a/example/transports/grpc/client/middleware.go +++ b/example/transports/grpc/client/middleware.go @@ -23,10 +23,11 @@ import ( "encoding/json" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" - "github.com/reeflective/team/client" - "github.com/reeflective/team/example/transports/grpc/common" "google.golang.org/grpc" "google.golang.org/grpc/credentials" + + "github.com/reeflective/team/client" + "github.com/reeflective/team/example/transports/grpc/common" ) // TokenAuth extracts authentication metadata from contexts, diff --git a/example/transports/grpc/proto/client.pb.go b/example/transports/grpc/proto/client.pb.go index 50e85c7..881ee22 100644 --- a/example/transports/grpc/proto/client.pb.go +++ b/example/transports/grpc/proto/client.pb.go @@ -7,10 +7,11 @@ package proto import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( diff --git a/example/transports/grpc/proto/service.pb.go b/example/transports/grpc/proto/service.pb.go index 7ba84d0..325502d 100644 --- a/example/transports/grpc/proto/service.pb.go +++ b/example/transports/grpc/proto/service.pb.go @@ -7,9 +7,10 @@ package proto import ( + reflect "reflect" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" ) const ( diff --git a/example/transports/grpc/proto/service_grpc.pb.go b/example/transports/grpc/proto/service_grpc.pb.go index e7dde5e..3414608 100644 --- a/example/transports/grpc/proto/service_grpc.pb.go +++ b/example/transports/grpc/proto/service_grpc.pb.go @@ -8,6 +8,7 @@ package proto import ( context "context" + grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" diff --git a/example/transports/grpc/server/middleware.go b/example/transports/grpc/server/middleware.go index cb9ce5b..81f5f54 100644 --- a/example/transports/grpc/server/middleware.go +++ b/example/transports/grpc/server/middleware.go @@ -25,13 +25,14 @@ import ( grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth" grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus" grpc_tags "github.com/grpc-ecosystem/go-grpc-middleware/tags" - "github.com/reeflective/team/example/transports/grpc/common" - "github.com/reeflective/team/server" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/status" + + "github.com/reeflective/team/example/transports/grpc/common" + "github.com/reeflective/team/server" ) // BufferingOptions returns a list of server options with max send/receive diff --git a/example/transports/grpc/server/server.go b/example/transports/grpc/server/server.go index 8c9b850..421b6a1 100644 --- a/example/transports/grpc/server/server.go +++ b/example/transports/grpc/server/server.go @@ -24,12 +24,13 @@ import ( "runtime/debug" "sync" - clientConn "github.com/reeflective/team/example/transports/grpc/client" - "github.com/reeflective/team/example/transports/grpc/proto" - teamserver "github.com/reeflective/team/server" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/test/bufconn" + + clientConn "github.com/reeflective/team/example/transports/grpc/client" + "github.com/reeflective/team/example/transports/grpc/proto" + teamserver "github.com/reeflective/team/server" ) const ( diff --git a/internal/certs/certs.go b/internal/certs/certs.go index f6bca0a..acab6b6 100644 --- a/internal/certs/certs.go +++ b/internal/certs/certs.go @@ -36,10 +36,11 @@ import ( "path/filepath" "time" - "github.com/reeflective/team/internal/assets" - "github.com/reeflective/team/internal/db" "github.com/sirupsen/logrus" "gorm.io/gorm" + + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/db" ) const ( diff --git a/internal/db/sql-cgo.go b/internal/db/sql-cgo.go index f329800..a5f279d 100644 --- a/internal/db/sql-cgo.go +++ b/internal/db/sql-cgo.go @@ -21,9 +21,9 @@ package db */ import ( - // Embedded SQLite instance. + // Embedded SQLite instance. _ "github.com/ncruces/go-sqlite3/embed" - // C-code. + // C-code. _ "github.com/ncruces/go-sqlite3" "gorm.io/driver/sqlite" diff --git a/internal/db/sql.go b/internal/db/sql.go index b8f86d3..6509086 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -23,12 +23,13 @@ import ( "fmt" "time" - "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" + + "github.com/reeflective/team/internal/log" ) const ( diff --git a/internal/log/log.go b/internal/log/log.go index b31cccf..0219661 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -23,8 +23,9 @@ import ( "io" "path/filepath" - "github.com/reeflective/team/internal/assets" "github.com/sirupsen/logrus" + + "github.com/reeflective/team/internal/assets" ) const ( diff --git a/server/commands/commands.go b/server/commands/commands.go index ba1030f..1e0c766 100644 --- a/server/commands/commands.go +++ b/server/commands/commands.go @@ -21,13 +21,14 @@ package commands import ( "fmt" + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/reeflective/team/client" cli "github.com/reeflective/team/client/commands" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/server" - "github.com/rsteube/carapace" - "github.com/spf13/cobra" - "github.com/spf13/pflag" ) // Generate returns a "teamserver" command root and its tree for teamserver (server-side) management. diff --git a/server/commands/completers.go b/server/commands/completers.go index 40c2d12..1b336ce 100644 --- a/server/commands/completers.go +++ b/server/commands/completers.go @@ -23,9 +23,10 @@ import ( "net" "strings" + "github.com/rsteube/carapace" + "github.com/reeflective/team/client" "github.com/reeflective/team/server" - "github.com/rsteube/carapace" ) // interfacesCompleter completes interface addresses on the client host. diff --git a/server/commands/teamserver.go b/server/commands/teamserver.go index 4a3fff0..6b16e42 100644 --- a/server/commands/teamserver.go +++ b/server/commands/teamserver.go @@ -28,12 +28,13 @@ import ( "strings" "github.com/jedib0t/go-pretty/v6/table" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/log" "github.com/reeflective/team/internal/systemd" "github.com/reeflective/team/server" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" ) func daemoncmd(serv *server.Server) func(cmd *cobra.Command, args []string) error { diff --git a/server/commands/user.go b/server/commands/user.go index 821d656..92b6f89 100644 --- a/server/commands/user.go +++ b/server/commands/user.go @@ -8,13 +8,13 @@ import ( "path/filepath" "strings" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/reeflective/team/client" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" - "github.com/reeflective/team/internal/log" "github.com/reeflective/team/server" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" ) func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Command, args []string) { diff --git a/server/config.go b/server/config.go index 5755247..d1d195b 100644 --- a/server/config.go +++ b/server/config.go @@ -27,10 +27,10 @@ import ( "path/filepath" "time" + "github.com/sirupsen/logrus" + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" - "github.com/reeflective/team/internal/log" - "github.com/sirupsen/logrus" ) const ( diff --git a/server/core.go b/server/core.go index 6f562c4..e81eda5 100644 --- a/server/core.go +++ b/server/core.go @@ -24,14 +24,15 @@ import ( "runtime" "sync" + "github.com/sirupsen/logrus" + "gorm.io/gorm" + "github.com/reeflective/team" "github.com/reeflective/team/client" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/db" "github.com/reeflective/team/internal/version" - "github.com/sirupsen/logrus" - "gorm.io/gorm" ) // Server is the core driver of an application teamserver. diff --git a/server/db.go b/server/db.go index a3c16be..9c085af 100644 --- a/server/db.go +++ b/server/db.go @@ -25,10 +25,11 @@ import ( "path" "path/filepath" + "gorm.io/gorm" + + "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/db" - "github.com/reeflective/team/internal/log" - "gorm.io/gorm" ) const ( diff --git a/server/directories.go b/server/directories.go index 044ca96..b100e21 100644 --- a/server/directories.go +++ b/server/directories.go @@ -24,7 +24,6 @@ import ( "path/filepath" "github.com/reeflective/team/internal/assets" - "github.com/reeflective/team/internal/log" ) // HomeDir returns the root application directory (~/.app/ by default). diff --git a/server/log.go b/server/log.go index 7b1729c..77da552 100644 --- a/server/log.go +++ b/server/log.go @@ -22,8 +22,9 @@ import ( "fmt" "path/filepath" - "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" + + "github.com/reeflective/team/internal/log" ) // NamedLogger returns a new logging "thread" with two fields (optional) diff --git a/server/options.go b/server/options.go index fe0b148..6d0393d 100644 --- a/server/options.go +++ b/server/options.go @@ -23,10 +23,11 @@ import ( "os" "strings" - "github.com/reeflective/team/internal/assets" - "github.com/reeflective/team/internal/db" "github.com/sirupsen/logrus" "gorm.io/gorm" + + "github.com/reeflective/team/internal/assets" + "github.com/reeflective/team/internal/db" ) const noTeamdir = "no team subdirectory" From f5b58ee8aca6d9b9f09dd591d420194ce1c789f5 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 20:01:15 +0200 Subject: [PATCH 30/40] Fix windows action --- .github/workflows/go.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 45db49f..b954313 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -57,10 +57,6 @@ jobs: with: go-version: 1.21 - - name: Version information - run: bash teamserver_version_info - working-directory: internal/version - - name: Teamclient example working-directory: example/teamclient run: go build -v . From 754c8ea819e24d57b5cefd0ea968edb41c6ddae7 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 22:12:25 +0200 Subject: [PATCH 31/40] Finish server examples code --- client/client.go | 3 +- client/config.go | 3 +- client/log.go | 3 +- client/options.go | 6 +- example/teamclient/main.go | 5 +- example/teamserver/main.go | 163 ++++++++++++++++++++++++++++++++----- server/config.go | 3 +- server/core.go | 5 +- server/db.go | 3 +- server/log.go | 3 +- server/options.go | 5 +- server/server.go | 1 + 12 files changed, 159 insertions(+), 44 deletions(-) diff --git a/client/client.go b/client/client.go index 5669896..44be641 100644 --- a/client/client.go +++ b/client/client.go @@ -24,11 +24,10 @@ import ( "runtime" "sync" - "github.com/sirupsen/logrus" - "github.com/reeflective/team" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/version" + "github.com/sirupsen/logrus" ) // Client is the core driver of an application teamclient. diff --git a/client/config.go b/client/config.go index a7a8023..ee616aa 100644 --- a/client/config.go +++ b/client/config.go @@ -29,11 +29,10 @@ import ( "path/filepath" "sort" - "gopkg.in/AlecAivazis/survey.v1" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/command" + "gopkg.in/AlecAivazis/survey.v1" ) const ( diff --git a/client/log.go b/client/log.go index b4e9a36..ed602c2 100644 --- a/client/log.go +++ b/client/log.go @@ -23,9 +23,8 @@ import ( "io" "path/filepath" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" ) // NamedLogger returns a new logging "thread" with two fields (optional) diff --git a/client/options.go b/client/options.go index bddf81a..9a321e0 100644 --- a/client/options.go +++ b/client/options.go @@ -24,9 +24,8 @@ import ( "os" "strings" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/assets" + "github.com/sirupsen/logrus" ) const noTeamdir = "no team subdirectory" @@ -113,6 +112,9 @@ func WithInMemory() Options { // WithConfig sets the client to use a given remote teamserver configuration which // to connect to, instead of using default on-disk user/application configurations. +// This function will be very useful to library users who wish to implement specific +// remote teamserver selection & connection strategies, depending on the domains and +// and use cases of these tools. func WithConfig(config *Config) Options { return func(opts *opts) { opts.config = config diff --git a/example/teamclient/main.go b/example/teamclient/main.go index ded0559..4561db3 100644 --- a/example/teamclient/main.go +++ b/example/teamclient/main.go @@ -3,11 +3,10 @@ package main import ( "log" - "github.com/rsteube/carapace" - "github.com/reeflective/team/client" "github.com/reeflective/team/client/commands" grpc "github.com/reeflective/team/example/transports/grpc/client" + "github.com/rsteube/carapace" ) // main shows how to use a remote teamclient with a gRPC backend (transport & RPC). @@ -51,5 +50,3 @@ func main() { log.Fatal(err) } } - -func mainPreCommands() {} diff --git a/example/teamserver/main.go b/example/teamserver/main.go index 61803af..3f7ec85 100644 --- a/example/teamserver/main.go +++ b/example/teamserver/main.go @@ -3,14 +3,38 @@ package main import ( "log" - "github.com/rsteube/carapace" - "github.com/reeflective/team/client" grpc "github.com/reeflective/team/example/transports/grpc/server" "github.com/reeflective/team/server" "github.com/reeflective/team/server/commands" + "github.com/rsteube/carapace" ) +// mainSmallest is the smallest example of a teamserver usage. +// The latter can only serve itself in-memory, since there are no +// remote teamserver listener stacks registered with it. Still, the +// teamserver functionality is complete and works identically regardless. +func mainSmallest() { + teamserver, err := server.New("smallserver") + if err != nil { + log.Fatal(err) + } + + // Generate a tree of server-side commands: this tree also has client-only + // commands as a subcommand "client" of the "teamserver" command root here. + serverCmds := commands.Generate(teamserver, teamserver.Self()) + serverCmds.Use = "smallserver" + + // Generate completions for the tree. + carapace.Gen(serverCmds) + + // Run our teamserver binary. + err = serverCmds.Execute() + if err != nil { + log.Fatal(err) + } +} + // main shows how to use a teamserver and teamclient with gRPC backends (transport & RPC). func main() { // 1) Teamserver & listeners @@ -77,6 +101,7 @@ func main() { } } +// mainSmallGRPC is the equivalent of main, without comments. func mainSmallGRPC() { // Server gTeamserver := grpc.NewListener() @@ -103,41 +128,139 @@ func mainSmallGRPC() { } } -func mainSmallest() { - teamserver, err := server.New("smallserver") +// mainNoCommands illustrates the fact (without much proof and code) that the teamclient +// and teamserver toolsets are not restrained to CLI usage nor have any obligation to use +// and expose themselves via a CLI. +// On the other hand, some programs may wish to offer it in specific circumstances, or even +// make use of it on the teamclient-side but not on the teamserver. Many setups are possible. +func mainNoCommands() { + // Server + gTeamserver := grpc.NewListener() + + teamserver, err := server.New("teamserver", server.WithListener(gTeamserver)) if err != nil { log.Fatal(err) } - // Generate a tree of server-side commands: this tree also has client-only - // commands as a subcommand "client" of the "teamserver" command root here. - serverCmds := commands.Generate(teamserver, teamserver.Self()) - serverCmds.Use = "smallserver" + // Note that we don't create a self-client for the teamserver: we don't need to have + // any teamclient interaction with the teamserver, and we just want to start/stop it + // from our code. + // + // Instead, let's first start a listener job on some address: this call is non blocking, + // and should we want to keep control of the listener job, we can use the returned ID. + listenerID, err := teamserver.ServeAddr("grpc/mTLS", "localhost", 31350) + if err != nil { + log.Fatal(err) + } - // Generate completions for the tree. - carapace.Gen(serverCmds) + // We can kill the listener from code like this. + err = teamserver.ListenerClose(listenerID) + if err != nil { + log.Fatal(err) + } - // Run our teamserver binary. - err = serverCmds.Execute() + // Finally, simply ask the server to start the daemon (blocking), which also starts + // all listeners that might be saved as persistent jobs. To be noted, you will typically + // favor the above ServeAddr() function in your code rather than the daemon one below, + // since -while being entirely possible- the latter will likely be favored by CLI users. + // + // Note that we don't pass the name of the listener stack we want to use: the daemon + // function always uses the first listener backend that has been registered to the server. + err = teamserver.ServeDaemon("localhost", 31350) if err != nil { log.Fatal(err) } } +// mainIntegrated demonstrates a use case where the library user might already have an existing, +// established and/or working program. This program will naturally already dispose of core things +// like loggers, database configurations or backends, specific directories for output, etc. +// +// This example therefore shows how to use some other options to tightly integrate the teamserver +// toolset to such programs, while maintaining a strictly identical behavior and function set. +// +// Note that we use nil pointers everywhere in those functions, so this function is very much +// unsafe to run as is. It should be noted again, however, that the library tries to fail safe +// and as early as possible, as illustrated by the various errors returned in examples above. +func mainIntegrated() { + // Use the classic gRPC example backend. + gTeamserver := grpc.NewListener() + + var serverOpts []server.Options + serverOpts = append(serverOpts, + // Filesystem + server.WithHomeDirectory("~/.config"), // If we use an appdirectory different from ~/.app/directory . + server.WithTeamDirectory(""), // We might want the teamserver-specific output not to use a specific subdir in it. + + // Logging. + server.WithLogger(nil), // We might have a fully set-up logger, with multiple output destinations. + server.WithLogFile("path/to/log.file"), // Or we are fine with default teamserver logger, but a specific file. + + // Network (listeners and settings). + server.WithDefaultPort(31340), // Default port of daemon/listeners. + server.WithListener(gTeamserver), // Please see above examples, and the documentation. Any number of them can be registered. + server.WithListener(nil), // Another listener/RPC backend stack used/needed by your application. + + // Database (stores users certificates) + server.WithDatabase(nil), // Either pass the teamserver a running DB to store/fetch users certificates data. + server.WithDatabaseConfig(nil), // Or a specific configuration to use for connecting to one. + ) + + // Pass those options at creation time: some of them cannot be passed later, + // while others can (eg, listener backends can be added and listener configs + // chosen at any time). + teamserver, err := server.New("teamserver", serverOpts...) + if err != nil { + log.Fatal(err) + } + + // Again, note that we don't pass the name of the listener stack we want to use: the daemon + // function always uses the first listener backend that has been registered to the server. + err = teamserver.ServeDaemon("localhost", 31350) + if err != nil { + log.Fatal(err) + } +} + +// mainInMemory adapts the mainSmallest example with options to instruct the teamserver +// to never touch the host filesystem: all filesystem calls are redirected to an in-memory +// filesystem (which therefore holds all log files and contents in memory), and an in-memory +// SQLite database instance. func mainInMemory() { + var serverOpts []server.Options + serverOpts = append(serverOpts, + server.WithInMemory(), + server.WithDefaultPort(31340), // Default port of daemon/listeners. + ) + + // Pass those options at creation time: some of them cannot be passed later, + // while others can (eg, listener backends can be added and listener configs + // chosen at any time). + teamserver, err := server.New("teamserver", serverOpts...) + if err != nil { + log.Fatal(err) + } + + // Pass specific options for the teamserver + // self-client, to provide identical behavior. var clientOpts []client.Options clientOpts = append(clientOpts, client.WithInMemory(), ) - var serverOpts []client.Options - serverOpts = append(serverOpts, - client.WithInMemory(), - ) -} + // Ask the teamserver to create its own teamclient (without any RPC client backend). + teamclient := teamserver.Self(clientOpts...) -func mainIntegrated() {} + // Generate a tree of server-side commands: this tree also has client-only + // commands as a subcommand "client" of the "teamserver" command root here. + serverCmds := commands.Generate(teamserver, teamclient) -func mainCustom() {} + // Generate completions for the tree. + carapace.Gen(serverCmds) -func mainNoCommands() {} + // Run our teamserver binary. + err = serverCmds.Execute() + if err != nil { + log.Fatal(err) + } +} diff --git a/server/config.go b/server/config.go index d1d195b..3b07a33 100644 --- a/server/config.go +++ b/server/config.go @@ -27,10 +27,9 @@ import ( "path/filepath" "time" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" ) const ( diff --git a/server/core.go b/server/core.go index e81eda5..6f562c4 100644 --- a/server/core.go +++ b/server/core.go @@ -24,15 +24,14 @@ import ( "runtime" "sync" - "github.com/sirupsen/logrus" - "gorm.io/gorm" - "github.com/reeflective/team" "github.com/reeflective/team/client" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/db" "github.com/reeflective/team/internal/version" + "github.com/sirupsen/logrus" + "gorm.io/gorm" ) // Server is the core driver of an application teamserver. diff --git a/server/db.go b/server/db.go index 9c085af..687b8a5 100644 --- a/server/db.go +++ b/server/db.go @@ -25,11 +25,10 @@ import ( "path" "path/filepath" - "gorm.io/gorm" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/db" + "gorm.io/gorm" ) const ( diff --git a/server/log.go b/server/log.go index 77da552..7b1729c 100644 --- a/server/log.go +++ b/server/log.go @@ -22,9 +22,8 @@ import ( "fmt" "path/filepath" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" ) // NamedLogger returns a new logging "thread" with two fields (optional) diff --git a/server/options.go b/server/options.go index 6d0393d..fe0b148 100644 --- a/server/options.go +++ b/server/options.go @@ -23,11 +23,10 @@ import ( "os" "strings" - "github.com/sirupsen/logrus" - "gorm.io/gorm" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/db" + "github.com/sirupsen/logrus" + "gorm.io/gorm" ) const noTeamdir = "no team subdirectory" diff --git a/server/server.go b/server/server.go index a29e055..f6e47d0 100644 --- a/server/server.go +++ b/server/server.go @@ -167,6 +167,7 @@ func (ts *Server) ServeDaemon(host string, port uint16, opts ...Options) (err er // ServeAddr attempts to serve a listener stack identified by "name" (the listener should be registered // with the teamserver with WithListener() option), on a given host:port address, with any provided option. // If returns either a critical error raised by the listener, or the ID of the listener job, for control. +// The call is non-blocking, contrarily to the server.ServeDaemon() method. func (ts *Server) ServeAddr(name string, host string, port uint16, opts ...Options) (id string, err error) { // If server was not initialized yet, do it. // This at least will update any listener/server-specific options. From 6ba100963a50d670e07a442747c3d37fbd58ba8c Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 22:37:20 +0200 Subject: [PATCH 32/40] Fix imports and update survey version --- client/config.go | 2 +- go.mod | 5 +++-- go.sum | 38 ++++++++++++++++++++++++++------------ internal/db/sql.go | 3 +-- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/client/config.go b/client/config.go index acf1eec..daec0c5 100644 --- a/client/config.go +++ b/client/config.go @@ -29,7 +29,7 @@ import ( "path/filepath" "sort" - "gopkg.in/AlecAivazis/survey/v2" + "github.com/AlecAivazis/survey/v2" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" diff --git a/go.mod b/go.mod index 16d9836..142cad8 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/reeflective/team go 1.21 require ( + github.com/AlecAivazis/survey/v2 v2.3.7 github.com/gofrs/uuid v4.4.0+incompatible github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/jedib0t/go-pretty/v6 v6.4.6 - github.com/mattn/go-sqlite3 v1.14.17 github.com/ncruces/go-sqlite3 v0.8.4 github.com/ncruces/go-sqlite3/gormlite v0.8.4 github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e @@ -16,7 +16,6 @@ require ( github.com/spf13/pflag v1.0.5 google.golang.org/grpc v1.56.1 google.golang.org/protobuf v1.31.0 - gopkg.in/AlecAivazis/survey.v1 v1.8.8 gorm.io/driver/mysql v1.5.1 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.2 @@ -39,6 +38,7 @@ require ( github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/ncruces/julianday v0.1.5 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -50,6 +50,7 @@ require ( golang.org/x/mod v0.11.0 // indirect golang.org/x/net v0.9.0 // indirect golang.org/x/sys v0.11.0 // indirect + golang.org/x/term v0.7.0 // indirect golang.org/x/text v0.12.0 // indirect golang.org/x/tools v0.6.0 // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect diff --git a/go.sum b/go.sum index 825f0e9..4e417f5 100644 --- a/go.sum +++ b/go.sum @@ -4,15 +4,18 @@ cloud.google.com/go/compute v1.19.1 h1:am86mquDUgjGNWxiGn+5PGLbmgiWXlE/yNWpIpNvu cloud.google.com/go/compute v1.19.1/go.mod h1:6ylj3a05WF8leseCdIf77NK0g1ey+nj5IKd5/kvShxE= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -github.com/AlecAivazis/survey/v2 v2.0.5/go.mod h1:WYBhg6f0y/fNYUuesWQc0PKbJcEliGcYHB9sNT3Bg74= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= -github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -50,8 +53,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= -github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -75,8 +78,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -127,10 +128,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -141,14 +142,15 @@ github.com/tetratelabs/wazero v1.4.0 h1:9/MirYvmkJ/zSUOygKY/ia3t+e+RqIZXKbylIby1 github.com/tetratelabs/wazero v1.4.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -158,6 +160,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -168,6 +171,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -178,6 +183,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -185,18 +191,27 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -208,6 +223,7 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -234,8 +250,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/AlecAivazis/survey.v1 v1.8.8 h1:5UtTowJZTz1j7NxVzDGKTz6Lm9IWm8DDF6b7a2wq9VY= -gopkg.in/AlecAivazis/survey.v1 v1.8.8/go.mod h1:CaHjv79TCgAvXMSFJSVgonHXYWxnhzI3eoHtnX5UgUo= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/internal/db/sql.go b/internal/db/sql.go index 6509086..b8f86d3 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -23,13 +23,12 @@ import ( "fmt" "time" + "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" - - "github.com/reeflective/team/internal/log" ) const ( From bfaf8ef27a831b2234987e63149af86fc4f855be Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 22:39:48 +0200 Subject: [PATCH 33/40] Fix imports AGAIN --- client/client.go | 3 +-- client/config.go | 1 - client/log.go | 3 +-- client/options.go | 2 -- 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/client/client.go b/client/client.go index 5669896..44be641 100644 --- a/client/client.go +++ b/client/client.go @@ -24,11 +24,10 @@ import ( "runtime" "sync" - "github.com/sirupsen/logrus" - "github.com/reeflective/team" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/version" + "github.com/sirupsen/logrus" ) // Client is the core driver of an application teamclient. diff --git a/client/config.go b/client/config.go index daec0c5..2e6791e 100644 --- a/client/config.go +++ b/client/config.go @@ -30,7 +30,6 @@ import ( "sort" "github.com/AlecAivazis/survey/v2" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/command" diff --git a/client/log.go b/client/log.go index b4e9a36..ed602c2 100644 --- a/client/log.go +++ b/client/log.go @@ -23,9 +23,8 @@ import ( "io" "path/filepath" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" ) // NamedLogger returns a new logging "thread" with two fields (optional) diff --git a/client/options.go b/client/options.go index dabb195..9a321e0 100644 --- a/client/options.go +++ b/client/options.go @@ -26,8 +26,6 @@ import ( "github.com/reeflective/team/internal/assets" "github.com/sirupsen/logrus" - - "github.com/reeflective/team/internal/assets" ) const noTeamdir = "no team subdirectory" From c8e831357c5e7b4e75096d03f70c5e45c50524fa Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 23:17:38 +0200 Subject: [PATCH 34/40] Fix wrong server configs directory usage --- server/config.go | 12 +++++------- server/core.go | 5 ++--- server/db.go | 5 ++--- server/directories.go | 15 ++++++++++++++- server/log.go | 3 +-- server/options.go | 5 ++--- 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/server/config.go b/server/config.go index d1d195b..28a5ffb 100644 --- a/server/config.go +++ b/server/config.go @@ -27,10 +27,9 @@ import ( "path/filepath" "time" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" ) const ( @@ -78,15 +77,14 @@ type Config struct { // ConfigPath returns the path to the server config.json file, on disk or in-memory. func (ts *Server) ConfigPath() string { - appDir := ts.TeamDir() - configDir := filepath.Join(appDir, "configs") + appDir := ts.ConfigsDir() - err := ts.fs.MkdirAll(configDir, assets.DirPerm) + err := ts.fs.MkdirAll(appDir, assets.DirPerm) if err != nil { - ts.log().Errorf("cannot write to %s config dir: %s", configDir, err) + ts.log().Errorf("cannot write to %s config dir: %s", appDir, err) } - serverConfigPath := filepath.Join(configDir, fmt.Sprintf("%s.%s", ts.Name(), command.ServerConfigExt)) + serverConfigPath := filepath.Join(appDir, fmt.Sprintf("%s.%s", ts.Name(), command.ServerConfigExt)) return serverConfigPath } diff --git a/server/core.go b/server/core.go index e81eda5..6f562c4 100644 --- a/server/core.go +++ b/server/core.go @@ -24,15 +24,14 @@ import ( "runtime" "sync" - "github.com/sirupsen/logrus" - "gorm.io/gorm" - "github.com/reeflective/team" "github.com/reeflective/team/client" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/db" "github.com/reeflective/team/internal/version" + "github.com/sirupsen/logrus" + "gorm.io/gorm" ) // Server is the core driver of an application teamserver. diff --git a/server/db.go b/server/db.go index 9c085af..7886e77 100644 --- a/server/db.go +++ b/server/db.go @@ -25,11 +25,10 @@ import ( "path" "path/filepath" - "gorm.io/gorm" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/db" + "gorm.io/gorm" ) const ( @@ -62,7 +61,7 @@ func (ts *Server) DatabaseConfig() *db.Config { // GetDatabaseConfigPath - File path to config.json. func (ts *Server) dbConfigPath() string { - appDir := ts.ConfigPath() + appDir := ts.ConfigsDir() log := ts.NamedLogger("config", "database") dbFileName := fmt.Sprintf("%s.%s", ts.Name()+"_database", command.ServerConfigExt) databaseConfigPath := filepath.Join(appDir, dbFileName) diff --git a/server/directories.go b/server/directories.go index b100e21..af75c7b 100644 --- a/server/directories.go +++ b/server/directories.go @@ -67,7 +67,7 @@ func (ts *Server) TeamDir() string { return dir } -// LogsDir returns the directory of the client (~/.app-server/logs), creating +// LogsDir returns the log directory of the server (~/.app-server/logs), creating // the directory if needed, or logging a fatal event if failing to create it. func (ts *Server) LogsDir() string { logDir := path.Join(ts.TeamDir(), assets.DirLogs) @@ -80,6 +80,19 @@ func (ts *Server) LogsDir() string { return logDir } +// Configs returns the configs directory of the server (~/.app-server/logs), creating +// the directory if needed, or logging a fatal event if failing to create it. +func (ts *Server) ConfigsDir() string { + logDir := path.Join(ts.TeamDir(), assets.DirConfigs) + + err := ts.fs.MkdirAll(logDir, assets.DirPerm) + if err != nil { + ts.log().Errorf("cannot write to %s root dir: %s", logDir, err) + } + + return logDir +} + // CertificatesDir returns the directory storing users CA PEM files as backup, // (~/.app/teamserver/certs), either on-disk or in-memory if the teamserver is. func (ts *Server) CertificatesDir() string { diff --git a/server/log.go b/server/log.go index 77da552..7b1729c 100644 --- a/server/log.go +++ b/server/log.go @@ -22,9 +22,8 @@ import ( "fmt" "path/filepath" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/log" + "github.com/sirupsen/logrus" ) // NamedLogger returns a new logging "thread" with two fields (optional) diff --git a/server/options.go b/server/options.go index 6d0393d..fe0b148 100644 --- a/server/options.go +++ b/server/options.go @@ -23,11 +23,10 @@ import ( "os" "strings" - "github.com/sirupsen/logrus" - "gorm.io/gorm" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/db" + "github.com/sirupsen/logrus" + "gorm.io/gorm" ) const noTeamdir = "no team subdirectory" From 83753bc8e373fd4516dfbe0a00f49c231c8b2ed5 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Thu, 17 Aug 2023 23:54:03 +0200 Subject: [PATCH 35/40] Fixes to security alerts --- example/README.md | 2 +- internal/certs/certs.go | 9 ++++----- internal/log/cli.go | 6 ++++-- internal/log/log.go | 3 +-- server/core.go | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/example/README.md b/example/README.md index bce37d7..2069da0 100644 --- a/example/README.md +++ b/example/README.md @@ -58,7 +58,7 @@ number of transport/RPC listener/server backends to your core application teamse RPC backend. This file is good in that it shows you clearly how to use the teamserver as a core driver for any application-specific teamserving process. For example it shows how to query the teamserver users, request their connection/token credentials, authenticate them, and log all steps - with the teamserver loggers. + with the teamserver loggers. 4) `transports/grpc/server/middleware.go` shows a quite complex but secure use of gRPC middleware using the teamserver authentication and logging toolset. Note that gRPC is a quite beefy stack, and not very idiomatic for Go. Don't be too scared at this code if you don't understand it at first, since diff --git a/internal/certs/certs.go b/internal/certs/certs.go index acab6b6..d2377ea 100644 --- a/internal/certs/certs.go +++ b/internal/certs/certs.go @@ -36,11 +36,10 @@ import ( "path/filepath" "time" - "github.com/sirupsen/logrus" - "gorm.io/gorm" - "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/db" + "github.com/sirupsen/logrus" + "gorm.io/gorm" ) const ( @@ -90,8 +89,8 @@ func NewManager(filesystem *assets.FS, db *gorm.DB, logger *logrus.Entry, appNam return certs } -func (m *Manager) db() *gorm.DB { - return m.database.Session(&gorm.Session{ +func (c *Manager) db() *gorm.DB { + return c.database.Session(&gorm.Session{ FullSaveAssociations: true, }) } diff --git a/internal/log/cli.go b/internal/log/cli.go index 302d47d..5c6963f 100644 --- a/internal/log/cli.go +++ b/internal/log/cli.go @@ -41,11 +41,13 @@ const ( fieldPackage = "logger" fieldMessage = "message" - PackageFieldKey = "teamserver_pkg" - minimumPackagePad = 11 ) +// PackageFieldKey is used to identify the name of the package +// specified by teamclients and teamservers named loggers. +const PackageFieldKey = "teamserver_pkg" + // stdioHook combines a stdout hook (info/debug/trace), // and a stderr hook (warn/error/fatal/panic). type stdioHook struct { diff --git a/internal/log/log.go b/internal/log/log.go index 0219661..b31cccf 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -23,9 +23,8 @@ import ( "io" "path/filepath" - "github.com/sirupsen/logrus" - "github.com/reeflective/team/internal/assets" + "github.com/sirupsen/logrus" ) const ( diff --git a/server/core.go b/server/core.go index 6f562c4..ea9f9a7 100644 --- a/server/core.go +++ b/server/core.go @@ -159,14 +159,14 @@ func (ts *Server) Self(opts ...client.Options) *client.Client { return teamclient } -// Version implements team.Client.VersionClient() interface +// VersionClient implements team.Client.VersionClient() interface // method, so that the teamserver can be a teamclient of itself. // This simply returns the server.VersionServer() output. func (ts *Server) VersionClient() (team.Version, error) { return ts.VersionServer() } -// Version returns the teamserver binary version information. +// VersionServe returns the teamserver binary version information. func (ts *Server) VersionServer() (team.Version, error) { semVer := version.Semantic() compiled, _ := version.Compiled() From 9d570b3dd7ce0e156083eb2ba25b5739e34cdd61 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Wed, 20 Dec 2023 13:56:04 +0100 Subject: [PATCH 36/40] Update dependencies --- go.mod | 5 +++-- go.sum | 7 +++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 142cad8..8ff8abf 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,9 @@ require ( github.com/ncruces/go-sqlite3 v0.8.4 github.com/ncruces/go-sqlite3/gormlite v0.8.4 github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e - github.com/rsteube/carapace v0.37.3 + github.com/rsteube/carapace v0.47.4 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 google.golang.org/grpc v1.56.1 google.golang.org/protobuf v1.31.0 @@ -44,6 +44,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rsteube/carapace-shlex v0.1.1 // indirect github.com/stretchr/testify v1.8.2 // indirect github.com/tetratelabs/wazero v1.4.0 // indirect golang.org/x/crypto v0.8.0 // indirect diff --git a/go.sum b/go.sum index 4e417f5..761538e 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -116,12 +117,18 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rsteube/carapace v0.37.3 h1:Us0AnzZ0JiWVHmETSX8PBgp2UJCf/O7KhgSKSpokkII= github.com/rsteube/carapace v0.37.3/go.mod h1:jkLt41Ne2TD2xPuMdX/2O05Smhy8vMgG7O2TYvC0yOc= +github.com/rsteube/carapace v0.47.4 h1:LwnkFsvRxc2WhZjM63QS7sCi3DlM9XGuATQM5rehgps= +github.com/rsteube/carapace v0.47.4/go.mod h1:4ZC5bulItu9t9sZ5yPcHgPREd8rPf274Q732n+wfl/o= +github.com/rsteube/carapace-shlex v0.1.1 h1:fRQEBBKyYKm4TXUabm4tzH904iFWSmXJl3UZhMfQNYU= +github.com/rsteube/carapace-shlex v0.1.1/go.mod h1:zPw1dOFwvLPKStUy9g2BYKanI6bsQMATzDMYQQybo3o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From bb9d1e2e49569b7e05bfd7173226b74e12eff858 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Wed, 20 Dec 2023 14:01:14 +0100 Subject: [PATCH 37/40] Remove useless imports in cgo build --- internal/db/sql-cgo.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/db/sql-cgo.go b/internal/db/sql-cgo.go index a5f279d..7c3dc6f 100644 --- a/internal/db/sql-cgo.go +++ b/internal/db/sql-cgo.go @@ -21,11 +21,6 @@ package db */ import ( - // Embedded SQLite instance. - _ "github.com/ncruces/go-sqlite3/embed" - // C-code. - _ "github.com/ncruces/go-sqlite3" - "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" From f2791a9b0f1dcbb86de0795338164194bbf4b1d0 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Wed, 20 Dec 2023 14:07:12 +0100 Subject: [PATCH 38/40] Format --- .golangci.yml | 8 ++++---- internal/db/sql.go | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index b27a7fd..b150bee 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -184,9 +184,9 @@ linters: - godox # tool for detection of FIXME, TODO and other comments (style,cmt) - goerr113 # checks the errors handling expressions (style,err) # - gofmt # formats and checks for code simplification (fmt) - # - gofumpt # checks whether code was gofumpt-ed (fmt) + - gofumpt # checks whether code was gofumpt-ed (fmt) - goheader # checks if file header matches to pattern (style) - #- goimports # fixes imports, formats code same as gofmt (fmt,import) + - goimports # fixes imports, formats code same as gofmt (fmt,import) # - golint # Deprecated - gomnd # analyzer to detect magic numbers (style) - gomoddirectives # manage replace/retract/excludes directives in go.mod (style,mod) @@ -261,7 +261,6 @@ linters: - forbidigo # Forbids identifiers (style) - gochecknoglobals # checks that no global variables exist (style) - gochecknoinits # checks that no init functions are present (style) - - goimports # fixes imports, formats code same as gofmt (fmt,import) - lll # Report long lines (style) - promlinter # checks Prometheus metrics naming via promlint - rowserrcheck # checks if Err of rows is checked successfully (bugs,sql) @@ -281,7 +280,8 @@ linters: - wrapcheck # checks errors returned from external packages are wrapped (style,err) - tagliatelle # checks struct tags (style) - gofmt # formats and checks for code simplification (fmt) - - gofumpt # checks whether code was gofumpt-ed (fmt) + # - gofumpt # checks whether code was gofumpt-ed (fmt) + # - goimports # fixes imports, formats code same as gofmt (fmt,import) # Run only fast linters from enabled linters set (first run won't be fast) # Default: false diff --git a/internal/db/sql.go b/internal/db/sql.go index b8f86d3..6509086 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -23,12 +23,13 @@ import ( "fmt" "time" - "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" + + "github.com/reeflective/team/internal/log" ) const ( From e4c9c9194b6c9501f28b40bf1988ac3db89ba1c9 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Wed, 12 Feb 2025 02:38:16 +0100 Subject: [PATCH 39/40] Fix and clean the user permissions system --- client/commands/commands.go | 7 +++--- client/commands/import.go | 5 ++-- client/commands/users.go | 5 ++-- client/commands/version.go | 5 ++-- go.mod | 1 + go.sum | 7 ++---- internal/db/certificates.go | 2 ++ internal/db/sql.go | 3 +-- internal/db/user.go | 19 +++++++++++---- server/commands/commands.go | 10 ++++---- server/commands/completers.go | 9 ++++--- server/commands/teamserver.go | 7 +++--- server/commands/user.go | 11 +++++---- server/db.go | 2 +- server/options.go | 3 +-- server/users.go | 44 ++++++++++++++++++++++++----------- teamclient.go | 14 +++++++---- 17 files changed, 90 insertions(+), 64 deletions(-) diff --git a/client/commands/commands.go b/client/commands/commands.go index 21923a2..1416c6b 100644 --- a/client/commands/commands.go +++ b/client/commands/commands.go @@ -25,13 +25,12 @@ import ( "path/filepath" "strings" + "github.com/reeflective/team/client" + "github.com/reeflective/team/internal/command" "github.com/rsteube/carapace" "github.com/rsteube/carapace/pkg/style" "github.com/spf13/cobra" "github.com/spf13/pflag" - - "github.com/reeflective/team/client" - "github.com/reeflective/team/internal/command" ) // Generate returns a command tree to embed in client applications connecting @@ -108,7 +107,7 @@ func clientCommands(cli *client.Client) *cobra.Command { importCmd := &cobra.Command{ Use: "import", - Short: fmt.Sprintf("Import a teamserver client configuration file for %s", cli.Name()), + Short: "Import a teamserver client configuration file for " + cli.Name(), Run: importCmd(cli), ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{}, cobra.ShellCompDirectiveDefault diff --git a/client/commands/import.go b/client/commands/import.go index ff470c2..166a86c 100644 --- a/client/commands/import.go +++ b/client/commands/import.go @@ -22,11 +22,10 @@ import ( "encoding/json" "fmt" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/reeflective/team/client" "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) func importCmd(cli *client.Client) func(cmd *cobra.Command, args []string) { diff --git a/client/commands/users.go b/client/commands/users.go index 3b7f1ca..f3045c9 100644 --- a/client/commands/users.go +++ b/client/commands/users.go @@ -23,11 +23,10 @@ import ( "time" "github.com/jedib0t/go-pretty/v6/table" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/reeflective/team/client" "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) func usersCmd(cli *client.Client) func(cmd *cobra.Command, args []string) error { diff --git a/client/commands/version.go b/client/commands/version.go index 2920bca..975c0d9 100644 --- a/client/commands/version.go +++ b/client/commands/version.go @@ -22,11 +22,10 @@ import ( "fmt" "time" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/reeflective/team/client" "github.com/reeflective/team/internal/command" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) func versionCmd(cli *client.Client) func(cmd *cobra.Command, args []string) error { diff --git a/go.mod b/go.mod index 8ff8abf..be8410e 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/gofrs/uuid v4.4.0+incompatible github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/jedib0t/go-pretty/v6 v6.4.6 + github.com/lib/pq v1.10.9 github.com/ncruces/go-sqlite3 v0.8.4 github.com/ncruces/go-sqlite3/gormlite v0.8.4 github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e diff --git a/go.sum b/go.sum index 761538e..d37ece9 100644 --- a/go.sum +++ b/go.sum @@ -13,7 +13,6 @@ github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZx github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -81,6 +80,8 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -115,8 +116,6 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/rsteube/carapace v0.37.3 h1:Us0AnzZ0JiWVHmETSX8PBgp2UJCf/O7KhgSKSpokkII= -github.com/rsteube/carapace v0.37.3/go.mod h1:jkLt41Ne2TD2xPuMdX/2O05Smhy8vMgG7O2TYvC0yOc= github.com/rsteube/carapace v0.47.4 h1:LwnkFsvRxc2WhZjM63QS7sCi3DlM9XGuATQM5rehgps= github.com/rsteube/carapace v0.47.4/go.mod h1:4ZC5bulItu9t9sZ5yPcHgPREd8rPf274Q732n+wfl/o= github.com/rsteube/carapace-shlex v0.1.1 h1:fRQEBBKyYKm4TXUabm4tzH904iFWSmXJl3UZhMfQNYU= @@ -125,8 +124,6 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= diff --git a/internal/db/certificates.go b/internal/db/certificates.go index adb9a27..a51b57f 100644 --- a/internal/db/certificates.go +++ b/internal/db/certificates.go @@ -42,6 +42,8 @@ func (c *Certificate) BeforeCreate(tx *gorm.DB) (err error) { if err != nil { return err } + c.CreatedAt = time.Now() + return nil } diff --git a/internal/db/sql.go b/internal/db/sql.go index 6509086..b8f86d3 100644 --- a/internal/db/sql.go +++ b/internal/db/sql.go @@ -23,13 +23,12 @@ import ( "fmt" "time" + "github.com/reeflective/team/internal/log" "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" - - "github.com/reeflective/team/internal/log" ) const ( diff --git a/internal/db/user.go b/internal/db/user.go index de220b7..29039fa 100644 --- a/internal/db/user.go +++ b/internal/db/user.go @@ -22,16 +22,18 @@ import ( "time" "github.com/gofrs/uuid" + "github.com/lib/pq" "gorm.io/gorm" ) // User - A teamserver user. type User struct { - ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` - CreatedAt time.Time `gorm:"->;<-:create;"` - LastSeen time.Time - Name string - Token string `gorm:"uniqueIndex"` + ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` + CreatedAt time.Time `gorm:"->;<-:create;"` + LastSeen time.Time + Name string + Token string `gorm:"uniqueIndex"` + Permissions pq.StringArray `gorm:"type:text[]"` } // BeforeCreate - GORM hook. @@ -45,3 +47,10 @@ func (o *User) BeforeCreate(tx *gorm.DB) (err error) { return nil } + +type Permissions struct { + ID uuid.UUID `gorm:"primaryKey;->;<-:create;type:uuid;"` + CreatedAt time.Time `gorm:"->;<-:create;"` + LastSeen time.Time + Name string +} diff --git a/server/commands/commands.go b/server/commands/commands.go index 67d2f73..e66847d 100644 --- a/server/commands/commands.go +++ b/server/commands/commands.go @@ -21,14 +21,13 @@ package commands import ( "fmt" - "github.com/rsteube/carapace" - "github.com/spf13/cobra" - "github.com/spf13/pflag" - "github.com/reeflective/team/client" cli "github.com/reeflective/team/client/commands" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/server" + "github.com/rsteube/carapace" + "github.com/spf13/cobra" + "github.com/spf13/pflag" ) // Generate returns a "teamserver" command root and its tree for teamserver (server-side) management. @@ -121,6 +120,7 @@ func serverCommands(server *server.Server, client *client.Client) *cobra.Command if cmd.PersistentPreRunE != nil { cmd.PersistentPreRunE(cmd, args) } + if cmd.PreRunE != nil { cmd.PreRunE(cmd, args) } @@ -195,6 +195,7 @@ func serverCommands(server *server.Server, client *client.Client) *cobra.Command userFlags.StringP("save", "s", "", "directory/file in which to save config") userFlags.StringP("name", "n", "", "user name") userFlags.BoolP("system", "U", false, "Use the current OS user, and save its configuration directly in client dir") + userFlags.StringSliceP("permissions", "P", []string{}, "list of permission strings for custom RPC auth") userCmd.Flags().AddFlagSet(userFlags) userComps := make(carapace.ActionMap) @@ -221,6 +222,7 @@ func serverCommands(server *server.Server, client *client.Client) *cobra.Command if cmd.PersistentPreRunE != nil { cmd.PersistentPreRunE(cmd, args) } + if cmd.PreRunE != nil { cmd.PreRunE(cmd, args) } diff --git a/server/commands/completers.go b/server/commands/completers.go index 1b336ce..5bf98b8 100644 --- a/server/commands/completers.go +++ b/server/commands/completers.go @@ -23,10 +23,9 @@ import ( "net" "strings" - "github.com/rsteube/carapace" - "github.com/reeflective/team/client" "github.com/reeflective/team/server" + "github.com/rsteube/carapace" ) // interfacesCompleter completes interface addresses on the client host. @@ -75,10 +74,10 @@ func userCompleter(client *client.Client, server *server.Server) carapace.Comple } if len(results) == 0 { - return carapace.ActionMessage(fmt.Sprintf("%s teamserver has no users", server.Name())) + return carapace.ActionMessage(server.Name() + " teamserver has no users") } - return carapace.ActionValues(results...).Tag(fmt.Sprintf("%s teamserver users", server.Name())) + return carapace.ActionValues(results...).Tag(server.Name() + " teamserver users") } } @@ -136,6 +135,6 @@ func listenerTypeCompleter(client *client.Client, server *server.Server) carapac return carapace.ActionMessage(fmt.Sprintf("no additional listener types for %s teamserver", server.Name())) } - return carapace.ActionValues(results...).Tag(fmt.Sprintf("%s teamserver listener types", server.Name())) + return carapace.ActionValues(results...).Tag(server.Name() + " teamserver listener types") } } diff --git a/server/commands/teamserver.go b/server/commands/teamserver.go index 2cc8d50..efb6038 100644 --- a/server/commands/teamserver.go +++ b/server/commands/teamserver.go @@ -28,13 +28,12 @@ import ( "strings" "github.com/jedib0t/go-pretty/v6/table" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/reeflective/team/internal/command" "github.com/reeflective/team/internal/log" "github.com/reeflective/team/internal/systemd" "github.com/reeflective/team/server" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) func daemoncmd(serv *server.Server) func(cmd *cobra.Command, args []string) error { @@ -59,7 +58,7 @@ func daemoncmd(serv *server.Server) func(cmd *cobra.Command, args []string) erro // Also written to logs in the teamserver code. defer func() { if r := recover(); r != nil { - fmt.Fprintf(cmd.OutOrStdout(), "stacktrace from panic: \n"+string(debug.Stack())) + fmt.Fprintf(cmd.OutOrStdout(), "%s", "stacktrace from panic: \n"+string(debug.Stack())) } }() diff --git a/server/commands/user.go b/server/commands/user.go index 92b6f89..05682db 100644 --- a/server/commands/user.go +++ b/server/commands/user.go @@ -8,13 +8,12 @@ import ( "path/filepath" "strings" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/reeflective/team/client" "github.com/reeflective/team/internal/assets" "github.com/reeflective/team/internal/command" "github.com/reeflective/team/server" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" ) func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Command, args []string) { @@ -31,6 +30,7 @@ func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Comm lport, _ := cmd.Flags().GetUint16("port") save, _ := cmd.Flags().GetString("save") system, _ := cmd.Flags().GetBool("system") + perms, _ := cmd.Flags().GetStringSlice("permissions") if save == "" { save, _ = os.Getwd() @@ -57,6 +57,7 @@ func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Comm } } else { saveTo, _ = filepath.Abs(save) + userFile, err := os.Stat(saveTo) if !os.IsNotExist(err) && !userFile.IsDir() { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"File already exists %s\n", err) @@ -70,7 +71,7 @@ func createUserCmd(serv *server.Server, cli *client.Client) func(cmd *cobra.Comm fmt.Fprintf(cmd.OutOrStdout(), command.Info+"Generating new client certificate, please wait ... \n") - config, err := serv.UserCreate(name, lhost, lport) + config, err := serv.UserCreate(name, lhost, lport, perms...) if err != nil { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"%s\n", err) return @@ -145,8 +146,8 @@ func importCACmd(serv *server.Server) func(cmd *cobra.Command, args []string) { } importCA := &CA{} - err = json.Unmarshal(data, importCA) + err = json.Unmarshal(data, importCA) if err != nil { fmt.Fprintf(cmd.ErrOrStderr(), command.Warn+"Failed to parse file: %s\n", err) } diff --git a/server/db.go b/server/db.go index 7886e77..b967784 100644 --- a/server/db.go +++ b/server/db.go @@ -159,7 +159,7 @@ func (ts *Server) getDefaultDatabaseConfig() *db.Config { if ts.opts.inMemory { cfg.Database = db.SQLiteInMemoryHost } else { - cfg.Database = filepath.Join(ts.TeamDir(), fmt.Sprintf("%s.teamserver.db", ts.name)) + cfg.Database = filepath.Join(ts.TeamDir(), ts.name+".teamserver.db") } return cfg diff --git a/server/options.go b/server/options.go index fe0b148..1ea2933 100644 --- a/server/options.go +++ b/server/options.go @@ -19,7 +19,6 @@ package server */ import ( - "fmt" "os" "strings" @@ -77,7 +76,7 @@ func (ts *Server) apply(options ...Options) { // set once when created. ts.initOpts.Do(func() { // Application home directory. - homeDir := os.Getenv(fmt.Sprintf("%s_ROOT_DIR", strings.ToUpper(ts.name))) + homeDir := os.Getenv(strings.ToUpper(ts.name) + "_ROOT_DIR") if homeDir != "" { ts.homeDir = homeDir } else { diff --git a/server/users.go b/server/users.go index d94ac9d..58512f4 100644 --- a/server/users.go +++ b/server/users.go @@ -30,19 +30,22 @@ import ( "sync" "time" + "github.com/lib/pq" + "github.com/reeflective/team" "github.com/reeflective/team/client" "github.com/reeflective/team/internal/certs" "github.com/reeflective/team/internal/db" ) var namePattern = regexp.MustCompile("^[a-zA-Z0-9_-]*$") // Only allow alphanumeric chars +const permissionsSep = "," // UserCreate creates a new teamserver user, with all cryptographic material and server remote // endpoints needed by this user to connect to us. // // Certificate files and the API authentication token are saved into the teamserver database, // conformingly to its configured backend/filesystem (can be in-memory or on filesystem). -func (ts *Server) UserCreate(name string, lhost string, lport uint16) (*client.Config, error) { +func (ts *Server) UserCreate(name string, lhost string, lport uint16, perms ...string) (*client.Config, error) { if err := ts.initDatabase(); err != nil { return nil, ts.errorf("%w: %w", ErrDatabase, err) } @@ -70,8 +73,10 @@ func (ts *Server) UserCreate(name string, lhost string, lport uint16) (*client.C digest := sha256.Sum256([]byte(rawToken)) dbuser := &db.User{ - Name: name, - Token: hex.EncodeToString(digest[:]), + Name: name, + Token: hex.EncodeToString(digest[:]), + Permissions: pq.StringArray(perms), + // Permissions: strings.Join(perms, permissionsSep), } err = ts.dbSession().Save(dbuser).Error @@ -141,9 +146,9 @@ func (ts *Server) UserDelete(name string) error { // - No name, false for authenticated, and a database error, if was ignited now. // // This call updates the last time the user has been seen by the server. -func (ts *Server) UserAuthenticate(rawToken string) (name string, authorized bool, err error) { +func (ts *Server) UserAuthenticate(rawToken string) (*team.User, bool, error) { if err := ts.initDatabase(); err != nil { - return "", false, ts.errorf("%w: %w", ErrDatabase, err) + return nil, false, ts.errorf("%w: %w", ErrDatabase, err) } log := ts.NamedLogger("server", "auth") @@ -153,23 +158,34 @@ func (ts *Server) UserAuthenticate(rawToken string) (name string, authorized boo digest := sha256.Sum256([]byte(rawToken)) token := hex.EncodeToString(digest[:]) - if name, ok := ts.userTokens.Load(token); ok { + userFound, ok := ts.userTokens.Load(token) + + // If user is already connected or cached. + if ok { + user := userFound.(*team.User) + log.Debugf("Token in cache!") - ts.updateLastSeen(name.(string)) - return name.(string), true, nil + ts.updateLastSeen(user.Name) + + return user, true, nil } - user, err := ts.userByToken(token) - if err != nil || user == nil { - return "", false, ts.errorf("%w: %w", ErrUnauthenticated, err) + dbUser, err := ts.userByToken(token) + if err != nil || dbUser == nil { + return nil, false, ts.errorf("%w: %w", ErrUnauthenticated, err) } + // Transfer data to the exportable user type + user := &team.User{ + Name: dbUser.Name, + Permissions: []string(dbUser.Permissions), + } ts.updateLastSeen(user.Name) log.Debugf("Valid user token for %s", user.Name) - ts.userTokens.Store(token, user.Name) + ts.userTokens.Store(token, user) - return user.Name, true, nil + return user, true, nil } // UsersTLSConfig returns a server-side Mutual TLS configuration struct, ready to run. @@ -196,7 +212,7 @@ func (ts *Server) UsersTLSConfig() (*tls.Config, error) { _, _, err = ts.certs.UserServerGetCertificate() if errors.Is(err, certs.ErrCertDoesNotExist) { if _, _, err := ts.certs.UserServerGenerateCertificate(); err != nil { - return nil, ts.errorWith(log, err.Error()) + return nil, ts.errorWith(log, "%s", err.Error()) } } diff --git a/teamclient.go b/teamclient.go index 07fdefd..ddc0f3c 100644 --- a/teamclient.go +++ b/teamclient.go @@ -41,10 +41,16 @@ type Client interface { // be in possession of the user cryptographic materials required to serve him) // This type is returned by both team/clients and team/servers. type User struct { - Name string - Online bool - LastSeen time.Time - Clients int + Name string // Name of the user + Online bool // Are one or more of the user's clients connected. + LastSeen time.Time // Last time the user made an RPC call or something. + Clients int // Number of clients connected. + + // Permissions is a list of arbitrary strings that clients/servers + // might want to use for permissions: domain names, tools, tokens... + // These permissions can be specified with --permissions on the CLI, + // and will be always stored along with the user in the database. + Permissions []string } // Version returns complete version/compilation information for a given binary. From 849ae283f24eee7de2772923a7203bc22f06c6c9 Mon Sep 17 00:00:00 2001 From: maxlandon Date: Wed, 12 Feb 2025 16:31:18 +0100 Subject: [PATCH 40/40] Update cobra --- go.mod | 4 ++-- go.sum | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index be8410e..2b5d39e 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,8 @@ require ( github.com/psanford/memfs v0.0.0-20230130182539-4dbf7e3e865e github.com/rsteube/carapace v0.47.4 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.0 - github.com/spf13/pflag v1.0.5 + github.com/spf13/cobra v1.8.1 + github.com/spf13/pflag v1.0.6 google.golang.org/grpc v1.56.1 google.golang.org/protobuf v1.31.0 gorm.io/driver/mysql v1.5.1 diff --git a/go.sum b/go.sum index d37ece9..d3d6811 100644 --- a/go.sum +++ b/go.sum @@ -14,6 +14,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -126,8 +127,12 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=