diff --git a/Containerfile b/Containerfile index 4f8eec3..fbed505 100644 --- a/Containerfile +++ b/Containerfile @@ -2,7 +2,7 @@ FROM alpine:3.20 as builder RUN apk --no-cache add make binutils gcc libc-dev automake autoconf curl RUN curl -o /usr/local/lib/go.tar.gz https://dl.google.com/go/go1.24.4.linux-amd64.tar.gz -RUN cd /usr/local/lib && tar xzf go.tar.gz +RUN cd /usr/local/lib && tar xzf go.tar.gz && rm -f go.tar.gz RUN cd /usr/local/bin && ln -sf ../lib/go/bin/* . WORKDIR /app/src/ @@ -19,4 +19,4 @@ RUN chmod 1777 /var WORKDIR /app #USER daemon:daemon -ENTRYPOINT ["/app/sbin/certmanagerd"] +ENTRYPOINT ["/app/sbin/mbased"] diff --git a/Makefile.am b/Makefile.am index 8aa93fb..7102d1e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,25 +13,50 @@ mbased$(EXEEXT): $(mbased_SOURCES) $(EXTRA_mbased_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mbased$(EXEEXT) $(mbased_SOURCES) mbasedump_SOURCES = \ + cmd/mbasedump/rest.go \ cmd/mbasedump/printr.go \ cmd/mbasedump/main.go \ + cmd/mbasedump/dump.go \ cmd/mbasedump/util.go mbasedump$(EXEEXT): $(mbasedump_SOURCES) $(EXTRA_mbased_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mbasedump$(EXEEXT) $(mbasedump_SOURCES) -mbasectl_SOURCES = cmd/mbasectl/main.go \ - cmd/mbasectl/account.go \ - cmd/mbasectl/grant.go \ - cmd/mbasectl/dump.go +mbasectl_SOURCES = \ + cmd/mbasectl/main.go \ + cmd/mbasectl/util.go +EXTRA_mbasectl_SOURCES = \ + cmd/mbasectl/account/create.go \ + cmd/mbasectl/account/delete.go \ + cmd/mbasectl/account/list.go \ + cmd/mbasectl/account/printr.go \ + cmd/mbasectl/account/update.go \ + cmd/mbasectl/account/util.go \ + cmd/mbasectl/grant/create.go \ + cmd/mbasectl/grant/delete.go \ + cmd/mbasectl/grant/printr.go \ + cmd/mbasectl/grant/util.go mbasectl$(EXEEXT): $(mbasectl_SOURCES) $(EXTRA_mbased_SOURCES) env CGO_ENABLED=0 $(GO) build $(GOFLAGS) -o mbasectl$(EXEEXT) $(mbasectl_SOURCES) -mbaseadmin_SOURCES = cmd/mbaseadmin/main.go \ - cmd/mbaseadmin/account.go \ - cmd/mbaseadmin/grant.go +mbaseadmin_SOURCES = \ + cmd/mbaseadmin/main.go \ + cmd/mbaseadmin/util.go + +EXTRA_mbaseadmin_SOURCES = \ + cmd/mbaseadmin/account/create.go \ + cmd/mbaseadmin/account/delete.go \ + cmd/mbaseadmin/account/list.go \ + cmd/mbaseadmin/account/printr.go \ + cmd/mbaseadmin/account/update.go \ + cmd/mbaseadmin/account/util.go \ + cmd/mbaseadmin/grant/create.go \ + cmd/mbaseadmin/grant/delete.go \ + cmd/mbaseadmin/grant/printr.go \ + cmd/mbaseadmin/grant/util.go + mbaseadmin$(EXEEXT): $(mbaseadmin_SOURCES) $(EXTRA_mbased_SOURCES) env CGO_ENABLED=1 $(GO) build $(GOFLAGS) -o mbaseadmin$(EXEEXT) $(mbaseadmin_SOURCES) diff --git a/Makefile.in b/Makefile.in index 1e73d51..66895d3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -146,9 +146,11 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = -SOURCES = $(mbaseadmin_SOURCES) $(mbasectl_SOURCES) $(mbased_SOURCES) \ - $(EXTRA_mbased_SOURCES) $(mbasedump_SOURCES) -DIST_SOURCES = $(mbaseadmin_SOURCES) $(mbasectl_SOURCES) \ +SOURCES = $(mbaseadmin_SOURCES) $(EXTRA_mbaseadmin_SOURCES) \ + $(mbasectl_SOURCES) $(EXTRA_mbasectl_SOURCES) \ + $(mbased_SOURCES) $(EXTRA_mbased_SOURCES) $(mbasedump_SOURCES) +DIST_SOURCES = $(mbaseadmin_SOURCES) $(EXTRA_mbaseadmin_SOURCES) \ + $(mbasectl_SOURCES) $(EXTRA_mbasectl_SOURCES) \ $(mbased_SOURCES) $(EXTRA_mbased_SOURCES) $(mbasedump_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ @@ -322,18 +324,43 @@ AUTOMAKE_OPTIONS = foreign no-dependencies no-installinfo SUFFIXES = .go mbased_SOURCES = cmd/mbased/main.go mbasedump_SOURCES = \ + cmd/mbasedump/rest.go \ cmd/mbasedump/printr.go \ cmd/mbasedump/main.go \ + cmd/mbasedump/dump.go \ cmd/mbasedump/util.go -mbasectl_SOURCES = cmd/mbasectl/main.go \ - cmd/mbasectl/account.go \ - cmd/mbasectl/grant.go \ - cmd/mbasectl/dump.go +mbasectl_SOURCES = \ + cmd/mbasectl/main.go \ + cmd/mbasectl/util.go -mbaseadmin_SOURCES = cmd/mbaseadmin/main.go \ - cmd/mbaseadmin/account.go \ - cmd/mbaseadmin/grant.go +EXTRA_mbasectl_SOURCES = \ + cmd/mbasectl/account/create.go \ + cmd/mbasectl/account/delete.go \ + cmd/mbasectl/account/list.go \ + cmd/mbasectl/account/printr.go \ + cmd/mbasectl/account/update.go \ + cmd/mbasectl/account/util.go \ + cmd/mbasectl/grant/create.go \ + cmd/mbasectl/grant/delete.go \ + cmd/mbasectl/grant/printr.go \ + cmd/mbasectl/grant/util.go + +mbaseadmin_SOURCES = \ + cmd/mbaseadmin/main.go \ + cmd/mbaseadmin/util.go + +EXTRA_mbaseadmin_SOURCES = \ + cmd/mbaseadmin/account/create.go \ + cmd/mbaseadmin/account/delete.go \ + cmd/mbaseadmin/account/list.go \ + cmd/mbaseadmin/account/printr.go \ + cmd/mbaseadmin/account/update.go \ + cmd/mbaseadmin/account/util.go \ + cmd/mbaseadmin/grant/create.go \ + cmd/mbaseadmin/grant/delete.go \ + cmd/mbaseadmin/grant/printr.go \ + cmd/mbaseadmin/grant/util.go EXTRA_mbased_SOURCES = EXTRA_DIST = \ diff --git a/app/handler/account.go b/app/handler/account.go index a3e6922..8faebde 100644 --- a/app/handler/account.go +++ b/app/handler/account.go @@ -10,9 +10,9 @@ import ( "google.golang.org/grpc/status" ) -func (hand *Handler) Authentificate(ctx context.Context) (int64, error) { +func (hand *Handler) Authentificate(ctx context.Context) (string, error) { var err error - var accountID int64 + var accountID string meta, _ := metadata.FromIncomingContext(ctx) usernameArr := meta["username"] diff --git a/app/logic/account.go b/app/logic/account.go index 63a32ff..3d9052e 100644 --- a/app/logic/account.go +++ b/app/logic/account.go @@ -5,15 +5,15 @@ import ( "fmt" "time" - "mbase/app/descr" - "mbase/pkg/auxid" + "mbase/pkg/descr" + "mbase/pkg/auxuuid" "mbase/pkg/auxpwd" "mbase/pkg/mbctl" ) -func (lg *Logic) ValidateAcount(ctx context.Context, username, password string) (bool, int64, error) { +func (lg *Logic) ValidateAcount(ctx context.Context, username, password string) (bool, string, error) { var err error - var accountID int64 + var accountID string var valid bool lg.WaitRestoring() @@ -32,7 +32,7 @@ func (lg *Logic) ValidateAcount(ctx context.Context, username, password string) return valid, accountID, err } -func (lg *Logic) CreateAccount(ctx context.Context, accountID int64, params *mbctl.CreateAccountParams) (*mbctl.CreateAccountResult, error) { +func (lg *Logic) CreateAccount(ctx context.Context, accountID string, params *mbctl.CreateAccountParams) (*mbctl.CreateAccountResult, error) { var err error res := &mbctl.CreateAccountResult{} @@ -68,7 +68,7 @@ func (lg *Logic) CreateAccount(ctx context.Context, accountID int64, params *mbc now := time.Now().Format(time.RFC3339) passhash := auxpwd.MakeSHA256Hash([]byte(params.Password)) accountDescr := &descr.Account{ - ID: auxid.GenID(), + ID: auxuuid.NewUUID(), Username: params.Username, Passhash: passhash, Disabled: false, @@ -83,7 +83,7 @@ func (lg *Logic) CreateAccount(ctx context.Context, accountID int64, params *mbc return res, err } -func (lg *Logic) UpdateAccount(ctx context.Context, accountID int64, params *mbctl.UpdateAccountParams) (*mbctl.UpdateAccountResult, error) { +func (lg *Logic) UpdateAccount(ctx context.Context, accountID string, params *mbctl.UpdateAccountParams) (*mbctl.UpdateAccountResult, error) { var err error res := &mbctl.UpdateAccountResult{} @@ -102,7 +102,7 @@ func (lg *Logic) UpdateAccount(ctx context.Context, accountID int64, params *mbc var accountDescr *descr.Account var accountExists bool switch { - case params.AccountID != 0: + case params.AccountID != "": accountExists, accountDescr, err = lg.db.GetAccountByID(ctx, params.AccountID) if err != nil { return res, err @@ -140,7 +140,7 @@ func (lg *Logic) UpdateAccount(ctx context.Context, accountID int64, params *mbc return res, err } -func (lg *Logic) DeleteAccount(ctx context.Context, accountID int64, params *mbctl.DeleteAccountParams) (*mbctl.DeleteAccountResult, error) { +func (lg *Logic) DeleteAccount(ctx context.Context, accountID string, params *mbctl.DeleteAccountParams) (*mbctl.DeleteAccountResult, error) { var err error res := &mbctl.DeleteAccountResult{} @@ -159,7 +159,7 @@ func (lg *Logic) DeleteAccount(ctx context.Context, accountID int64, params *mbc var accountDescr *descr.Account var accountExists bool switch { - case params.AccountID != 0: + case params.AccountID != "": accountExists, accountDescr, err = lg.db.GetAccountByID(ctx, params.AccountID) if err != nil { return res, err @@ -186,7 +186,7 @@ func (lg *Logic) DeleteAccount(ctx context.Context, accountID int64, params *mbc return res, err } -func (lg *Logic) ListAccounts(ctx context.Context, accountID int64, params *mbctl.ListAccountsParams) (*mbctl.ListAccountsResult, error) { +func (lg *Logic) ListAccounts(ctx context.Context, accountID string, params *mbctl.ListAccountsParams) (*mbctl.ListAccountsResult, error) { var err error res := &mbctl.ListAccountsResult{ Accounts: make([]*mbctl.AccountShortDescr, 0), diff --git a/app/logic/database.go b/app/logic/database.go index bba6d4c..85714eb 100644 --- a/app/logic/database.go +++ b/app/logic/database.go @@ -4,8 +4,8 @@ import ( "context" "time" - "mbase/app/descr" - "mbase/pkg/auxid" + "mbase/pkg/descr" + "mbase/pkg/auxuuid" "mbase/pkg/auxpwd" ) @@ -23,9 +23,9 @@ func (lg *Logic) CleanDatabase(ctx context.Context) error { return err } -func (lg *Logic) SeedAccount(ctx context.Context) (int64, error) { +func (lg *Logic) SeedAccount(ctx context.Context) (string, error) { var err error - var accountID int64 + var accountID string accountDescrs, err := lg.db.ReducedListAccounts(ctx) if err != nil { return accountID, err @@ -35,7 +35,7 @@ func (lg *Logic) SeedAccount(ctx context.Context) (int64, error) { now := time.Now().Format(time.RFC3339) passhash := auxpwd.MakeSHA256Hash([]byte(defaultSeedPassword)) accountDescr := &descr.Account{ - ID: auxid.GenID(), + ID: auxuuid.NewUUID(), Username: defaultSeedUsername, Passhash: passhash, Disabled: false, @@ -63,9 +63,7 @@ func (lg *Logic) SeedAccount(ctx context.Context) (int64, error) { } } - } - return accountID, err } diff --git a/app/logic/dump.go b/app/logic/dump.go index 99f5d4b..cc64898 100644 --- a/app/logic/dump.go +++ b/app/logic/dump.go @@ -5,13 +5,13 @@ import ( "fmt" "time" - "mbase/app/descr" + "mbase/pkg/descr" "mbase/pkg/mbctl" "go.yaml.in/yaml/v4" ) -func (lg *Logic) GetDump(ctx context.Context, accountID int64, params *mbctl.GetDumpParams) (*mbctl.GetDumpResult, error) { +func (lg *Logic) GetDump(ctx context.Context, accountID string, params *mbctl.GetDumpParams) (*mbctl.GetDumpResult, error) { var err error res := &mbctl.GetDumpResult{} @@ -55,7 +55,7 @@ func (lg *Logic) GetDump(ctx context.Context, accountID int64, params *mbctl.Get return res, err } -func (lg *Logic) RestoreDump(ctx context.Context, accountID int64, params *mbctl.RestoreDumpParams) (*mbctl.RestoreDumpResult, error) { +func (lg *Logic) RestoreDump(ctx context.Context, accountID string, params *mbctl.RestoreDumpParams) (*mbctl.RestoreDumpResult, error) { var err error res := &mbctl.RestoreDumpResult{} diff --git a/app/logic/grants.go b/app/logic/grants.go index 948152b..4d375b1 100644 --- a/app/logic/grants.go +++ b/app/logic/grants.go @@ -5,12 +5,12 @@ import ( "fmt" "time" - "mbase/app/descr" - "mbase/pkg/auxid" + "mbase/pkg/descr" + "mbase/pkg/auxuuid" "mbase/pkg/mbctl" ) -func (lg *Logic) SetGrant(ctx context.Context, accountID int64, params *mbctl.SetGrantParams) (*mbctl.SetGrantResult, error) { +func (lg *Logic) SetGrant(ctx context.Context, accountID string, params *mbctl.SetGrantParams) (*mbctl.SetGrantResult, error) { var err error res := &mbctl.SetGrantResult{} @@ -44,7 +44,7 @@ func (lg *Logic) SetGrant(ctx context.Context, accountID int64, params *mbctl.Se var accountDescr *descr.Account var accountExists bool switch { - case params.AccountID != 0: + case params.AccountID != "": accountExists, accountDescr, err = lg.db.GetAccountByID(ctx, params.AccountID) if err != nil { return res, err @@ -70,7 +70,7 @@ func (lg *Logic) SetGrant(ctx context.Context, accountID int64, params *mbctl.Se } now := time.Now().Format(time.RFC3339) grantDescr := &descr.Grant{ - ID: auxid.GenID(), + ID: auxuuid.NewUUID(), AccountID: accountDescr.ID, CreatedAt: now, Operation: params.Operation, @@ -82,7 +82,7 @@ func (lg *Logic) SetGrant(ctx context.Context, accountID int64, params *mbctl.Se return res, err } -func (lg *Logic) DeleteGrant(ctx context.Context, accountID int64, params *mbctl.DeleteGrantParams) (*mbctl.DeleteGrantResult, error) { +func (lg *Logic) DeleteGrant(ctx context.Context, accountID string, params *mbctl.DeleteGrantParams) (*mbctl.DeleteGrantResult, error) { var err error res := &mbctl.DeleteGrantResult{} @@ -116,7 +116,7 @@ func (lg *Logic) DeleteGrant(ctx context.Context, accountID int64, params *mbctl var accountDescr *descr.Account var accountExists bool switch { - case params.AccountID != 0: + case params.AccountID != "": accountExists, accountDescr, err = lg.db.GetAccountByID(ctx, params.AccountID) if err != nil { return res, err diff --git a/app/maindb/account.go b/app/maindb/account.go index 999cef4..afd5fec 100644 --- a/app/maindb/account.go +++ b/app/maindb/account.go @@ -3,7 +3,7 @@ package maindb import ( "context" - "mbase/app/descr" + "mbase/pkg/descr" ) func (db *Database) InsertAccount(ctx context.Context, account *descr.Account) error { @@ -19,7 +19,7 @@ func (db *Database) InsertAccount(ctx context.Context, account *descr.Account) e return err } -func (db *Database) UpdateAccountByID(ctx context.Context, accountID int64, account *descr.Account) error { +func (db *Database) UpdateAccountByID(ctx context.Context, accountID string, account *descr.Account) error { var err error request := `UPDATE account SET username = $1, passhash = $2, disabled = $3, updated_at = $4 WHERE id = $5` @@ -52,7 +52,7 @@ func (db *Database) CompletedListAccounts(ctx context.Context) ([]descr.Account, return res, err } -func (db *Database) GetAccountByID(ctx context.Context, accountID int64) (bool, *descr.Account, error) { +func (db *Database) GetAccountByID(ctx context.Context, accountID string) (bool, *descr.Account, error) { var err error var res *descr.Account var exists bool @@ -91,7 +91,7 @@ func (db *Database) GetAccountByUsername(ctx context.Context, username string) ( return exists, res, err } -func (db *Database) DeleteAccountByID(ctx context.Context, accountID int64) error { +func (db *Database) DeleteAccountByID(ctx context.Context, accountID string) error { var err error request := `DELETE FROM account WHERE id = $1` diff --git a/app/maindb/database.go b/app/maindb/database.go index 2a0d8cd..a466c58 100644 --- a/app/maindb/database.go +++ b/app/maindb/database.go @@ -11,39 +11,9 @@ import ( ) const schema = ` - --- DROP TABLE IF EXISTS issuer; - CREATE TABLE IF NOT EXISTS issuer ( - id INT NOT NULL, - name TEXT NOT NULL, - cert TEXT NOT NULL, - key TEXT, - signer_id INT NOT NULL, - signer_name TEXT NOT NULL, - revoked BOOL - ); - CREATE UNIQUE INDEX IF NOT EXISTS issuer_index01 - ON issuer(id); - CREATE UNIQUE INDEX IF NOT EXISTS issuer_index02 - ON issuer(name); - - --- DROP TABLE IF EXISTS service; - CREATE TABLE IF NOT EXISTS service ( - id INT NOT NULL, - issuer_id INT NOT NULL, - issuer_name TEXT NOT NULL, - name TEXT NOT NULL, - cert TEXT NOT NULL, - key TEXT NOT NULL, - revoked BOOL - ); - CREATE UNIQUE INDEX IF NOT EXISTS service_index01 - ON service(id); - CREATE UNIQUE INDEX IF NOT EXISTS service_index02 - ON service(name); - --- DROP TABLE IF EXISTS account; CREATE TABLE IF NOT EXISTS account ( - id INT NOT NULL, + id TEXT NOT NULL, username TEXT NOT NULL, passhash TEXT NOT NULL, created_at TEXT NOT NULL, @@ -55,11 +25,10 @@ const schema = ` CREATE UNIQUE INDEX IF NOT EXISTS account_index02 ON account(username); - --- DROP TABLE IF EXISTS grant; CREATE TABLE IF NOT EXISTS grant ( - id INT NOT NULL, - account_id INT NOT NULL, + id TEXT NOT NULL, + account_id TEXT NOT NULL, operation TEXT NOT NULL, created_at TEXT NOT NULL ); diff --git a/app/maindb/grant.go b/app/maindb/grant.go index c79d875..1b33b9d 100644 --- a/app/maindb/grant.go +++ b/app/maindb/grant.go @@ -3,7 +3,7 @@ package maindb import ( "context" - "mbase/app/descr" + "mbase/pkg/descr" ) func (db *Database) InsertGrant(ctx context.Context, grant *descr.Grant) error { @@ -17,7 +17,7 @@ func (db *Database) InsertGrant(ctx context.Context, grant *descr.Grant) error { return err } -func (db *Database) ListGrantsByAccountID(ctx context.Context, accountID int64) ([]descr.Grant, error) { +func (db *Database) ListGrantsByAccountID(ctx context.Context, accountID string) ([]descr.Grant, error) { var err error request := `SELECT * FROM grant WHERE account_id = $1` res := make([]descr.Grant, 0) @@ -39,7 +39,7 @@ func (db *Database) ListGrants(ctx context.Context) ([]descr.Grant, error) { return res, err } -func (db *Database) GetGrant(ctx context.Context, accountID int64, operation string) (bool, *descr.Grant, error) { +func (db *Database) GetGrant(ctx context.Context, accountID, operation string) (bool, *descr.Grant, error) { var err error res := &descr.Grant{} request := `SELECT * FROM grant WHERE account_id = $1 AND operation = $2 LIMIT 1` @@ -56,7 +56,7 @@ func (db *Database) GetGrant(ctx context.Context, accountID int64, operation str return true, res, err } -func (db *Database) DeleteGrantByAccountID(ctx context.Context, grantID int64, operation string) error { +func (db *Database) DeleteGrantByAccountID(ctx context.Context, grantID, operation string) error { var err error request := `DELETE FROM grant WHERE account_id = $1 AND operation = $2` _, err = db.db.Exec(request, grantID, operation) @@ -66,7 +66,7 @@ func (db *Database) DeleteGrantByAccountID(ctx context.Context, grantID int64, o return err } -func (db *Database) DeleteAllGrantsForAccountID(ctx context.Context, grantID int64) error { +func (db *Database) DeleteAllGrantsForAccountID(ctx context.Context, grantID string) error { var err error request := `DELETE FROM grant WHERE account_id = $1` _, err = db.db.Exec(request, grantID) diff --git a/app/server/server.go b/app/server/server.go index 8f2bc82..edfef2f 100644 --- a/app/server/server.go +++ b/app/server/server.go @@ -12,7 +12,7 @@ import ( "mbase/app/config" "mbase/app/maindb" - "mbase/app/descr" + "mbase/pkg/descr" "mbase/app/logic" "mbase/pkg/aux509" "mbase/pkg/logger" diff --git a/cmd/mbaseadmin/account.go b/cmd/mbaseadmin/account/attic/account.gox similarity index 72% rename from cmd/mbaseadmin/account.go rename to cmd/mbaseadmin/account/attic/account.gox index 98f1a78..5b2cd5e 100644 --- a/cmd/mbaseadmin/account.go +++ b/cmd/mbaseadmin/account/attic/account.gox @@ -6,7 +6,7 @@ import ( "mbase/pkg/mbctl" ) -func (util *Util) CreateAccount(ctx context.Context, operID int64) (*mbctl.CreateAccountResult, error) { +func (util *Util) CreateAccount(ctx context.Context, operID string) (*mbctl.CreateAccountResult, error) { var err error res := &mbctl.CreateAccountResult{} @@ -21,7 +21,7 @@ func (util *Util) CreateAccount(ctx context.Context, operID int64) (*mbctl.Creat return res, err } -func (util *Util) DeleteAccount(ctx context.Context, operID int64) (*mbctl.DeleteAccountResult, error) { +func (util *Util) DeleteAccount(ctx context.Context, operID string) (*mbctl.DeleteAccountResult, error) { var err error res := &mbctl.DeleteAccountResult{} params := &mbctl.DeleteAccountParams{ @@ -35,7 +35,7 @@ func (util *Util) DeleteAccount(ctx context.Context, operID int64) (*mbctl.Delet return res, err } -func (util *Util) ListAccounts(ctx context.Context, operID int64) (*mbctl.ListAccountsResult, error) { +func (util *Util) ListAccounts(ctx context.Context, operID string) (*mbctl.ListAccountsResult, error) { var err error res := &mbctl.ListAccountsResult{} params := &mbctl.ListAccountsParams{} @@ -46,7 +46,7 @@ func (util *Util) ListAccounts(ctx context.Context, operID int64) (*mbctl.ListAc return res, err } -func (util *Util) UpdateAccount(ctx context.Context, operID int64) (*mbctl.UpdateAccountResult, error) { +func (util *Util) UpdateAccount(ctx context.Context, operID string) (*mbctl.UpdateAccountResult, error) { var err error res := &mbctl.UpdateAccountResult{} params := &mbctl.UpdateAccountParams{ diff --git a/cmd/mbaseadmin/grant.go b/cmd/mbaseadmin/account/attic/grant.gox similarity index 76% rename from cmd/mbaseadmin/grant.go rename to cmd/mbaseadmin/account/attic/grant.gox index 35270ac..abf9ad5 100644 --- a/cmd/mbaseadmin/grant.go +++ b/cmd/mbaseadmin/account/attic/grant.gox @@ -6,7 +6,7 @@ import ( "mbase/pkg/mbctl" ) -func (util *Util) SetGrant(ctx context.Context, operID int64) (*mbctl.SetGrantResult, error) { +func (util *Util) SetGrant(ctx context.Context, operID string) (*mbctl.SetGrantResult, error) { var err error res := &mbctl.SetGrantResult{} params := &mbctl.SetGrantParams{ @@ -24,7 +24,7 @@ func (util *Util) SetGrant(ctx context.Context, operID int64) (*mbctl.SetGrantRe return res, err } -func (util *Util) DeleteGrant(ctx context.Context, operID int64) (*mbctl.DeleteGrantResult, error) { +func (util *Util) DeleteGrant(ctx context.Context, operID string) (*mbctl.DeleteGrantResult, error) { var err error res := &mbctl.DeleteGrantResult{} params := &mbctl.DeleteGrantParams{ diff --git a/cmd/mbaseadmin/account/attic/main.gox b/cmd/mbaseadmin/account/attic/main.gox new file mode 100644 index 0000000..f6ae115 --- /dev/null +++ b/cmd/mbaseadmin/account/attic/main.gox @@ -0,0 +1,467 @@ +/* + * Copyright 2024 Oleg Borodin + */ + +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "time" + + "mbase/app/config" + "mbase/app/maindb" + "mbase/pkg/descr" + "mbase/app/logic" + + "sigs.k8s.io/yaml" +) + +const ( + rcFilename = ".certmanager.yaml" + + helpCmd = "help" + + createAccountCmd = "createAccount" + updateAccountCmd = "updateAccount" + deleteAccountCmd = "deleteAccount" + listAccountsCmd = "listAccounts" + + setGrantCmd = "setGrant" + deleteGrantCmd = "deleteGrant" + + initDatabaseCmd = "initDatabase" + seedAccountCmd = "seedAccount" +) + +func main() { + var err error + util := NewUtil() + err = util.Build() + if err != nil { + fmt.Printf("Build error: %v\n", err) + os.Exit(1) + } + err = util.Exec() + if err != nil { + fmt.Printf("Exec error: %v\n", err) + os.Exit(1) + } + os.Exit(0) +} + +type Util struct { + subCmd string + cmdTimeout int64 + + conf *config.Config + lg *logic.Logic + db *maindb.Database + state descr.Server + sfile string + + accessUsername string + accessPassword string + accountID int64 + username string + password string + disable bool + newUsername string + newPassword string + operation string + quiet bool +} + +func NewUtil() *Util { + var util Util + util.cmdTimeout = 120 + return &util +} + +func (util *Util) GetOpt() error { + var err error + + exeName := filepath.Base(os.Args[0]) + + flag.Int64Var(&util.cmdTimeout, "timeout", util.cmdTimeout, "command execution timeout") + flag.StringVar(&util.accessUsername, "user", util.accessUsername, "access login") + flag.StringVar(&util.accessPassword, "pass", util.accessPassword, "access password") + flag.BoolVar(&util.quiet, "quiet", util.quiet, "don't print result") + + help := func() { + fmt.Println("") + fmt.Printf("Usage: %s [option] command [command option]\n", exeName) + fmt.Printf("\n") + fmt.Printf(" %s, %s, %s, %s,\n", + createAccountCmd, + deleteAccountCmd, + listAccountsCmd, + updateAccountCmd) + fmt.Printf(" %s, %s\n", + setGrantCmd, + deleteGrantCmd) + fmt.Printf(" %s, %s\n", + initDatabaseCmd, + seedAccountCmd) + + fmt.Printf("\n") + fmt.Printf("Global options:\n") + flag.PrintDefaults() + fmt.Printf("\n") + } + flag.Usage = help + flag.Parse() + + args := flag.Args() + + var subCmd string + var subArgs []string + if len(args) > 0 { + subCmd = args[0] + subArgs = args[1:] + } + + util.subCmd = subCmd + + switch subCmd { + case helpCmd: + help() + return errors.New("Unknown command") + + case createAccountCmd: + flagSet := flag.NewFlagSet(createAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.StringVar(&util.password, "password", util.password, "user password") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteAccountCmd: + flagSet := flag.NewFlagSet(deleteAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case listAccountsCmd: + flagSet := flag.NewFlagSet(listAccountsCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case updateAccountCmd: + flagSet := flag.NewFlagSet(updateAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.StringVar(&util.newUsername, "newUsername", util.newUsername, "new user name") + flagSet.StringVar(&util.newPassword, "newPassword", util.newPassword, "new user password") + flagSet.BoolVar(&util.disable, "disable", util.disable, "disable account") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case setGrantCmd: + flagSet := flag.NewFlagSet(setGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteGrantCmd: + flagSet := flag.NewFlagSet(deleteGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case initDatabaseCmd: + flagSet := flag.NewFlagSet(initDatabaseCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + case seedAccountCmd: + flagSet := flag.NewFlagSet(seedAccountCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + default: + help() + return errors.New("Unknown command") + } + return err +} + +func (util *Util) Build() error { + var err error + + util.conf = config.NewConfig() + err = util.conf.ReadFile() + if err != nil { + return err + } + err = util.conf.ReadEnv() + if err != nil { + return err + } + + util.sfile = filepath.Join(util.conf.DataDir, "certmanager.yaml") + + db, err := maindb.NewDatabase(util.conf.DataDir) + if err != nil { + return err + } + err = db.OpenDatabase() + if err != nil { + return err + } + util.db = db + logicConfig := &logic.LogicConfig{ + Database: util.db, + } + util.lg, err = logic.NewLogic(logicConfig) + if err != nil { + return err + } + return err +} + +type Response struct { + Command string `json:"command" yaml:"command"` + Args []string `json:"args" yaml:"args"` + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` +} + +func (util *Util) Exec() error { + var err error + err = util.GetOpt() + if err != nil { + return err + } + + var timeout = time.Duration(util.cmdTimeout) * time.Second + ctx, close := context.WithTimeout(context.Background(), timeout) + defer close() + + var res any + + switch util.subCmd { + case initDatabaseCmd: + res, err = util.InitDatabase(ctx) + case seedAccountCmd: + res, err = util.SeedAccount(ctx) + default: + authOk, operID, localErr := util.lg.ValidateAcount(ctx, util.accessUsername, util.accessPassword) + if err != nil { + err = localErr + goto exit + } + if !authOk { + err = fmt.Errorf("Incorrect username or password") + goto exit + } + switch util.subCmd { + case createAccountCmd: + res, err = util.CreateAccount(ctx, operID) + case updateAccountCmd: + res, err = util.UpdateAccount(ctx, operID) + case listAccountsCmd: + res, err = util.ListAccounts(ctx, operID) + case deleteAccountCmd: + res, err = util.DeleteAccount(ctx, operID) + case setGrantCmd: + res, err = util.SetGrant(ctx, operID) + case deleteGrantCmd: + res, err = util.DeleteGrant(ctx, operID) + default: + err = errors.New("Unknown cli command") + } + } + +exit: + var resp Response + resp.Command = util.subCmd + resp.Args = os.Args + if err != nil { + resp.Error = true + resp.Message = fmt.Sprintf("%v", err) + } else { + resp.Result = res + } + + if !resp.Error && !util.quiet { + respBytes, _ := yaml.Marshal(resp) + fmt.Println(string(respBytes)) + } + return err +} + +type InitDatabaseRes struct{} + +func (util *Util) InitDatabase(ctx context.Context) (InitDatabaseRes, error) { + res := InitDatabaseRes{} + // Initialize database + + // Load state + err := util.LoadState() + if err != nil { + return res, err + } + if !util.state.DatabaseInitialized { + if util.db == nil { + err = fmt.Errorf("Nil db object") + return res, err + } + err := util.db.InitDatabase() + if err != nil { + return res, err + } + util.state.DatabaseInitialized = true + err = util.SaveState() + if err != nil { + return res, err + } + + } + return res, err +} + +type SeedAccountRes struct{} + +func (util *Util) SeedAccount(ctx context.Context) (SeedAccountRes, error) { + // Seed accounts + res := SeedAccountRes{} + _, err := util.lg.SeedAccount(ctx) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) LoadState() error { + var err error + _, err = os.Stat(util.sfile) + if os.IsNotExist(err) { + err = nil + return err + } + file, err := os.Open(util.sfile) + if err != nil { + return err + } + defer file.Close() + stateBytes, err := ioutil.ReadAll(file) + if err != nil { + return err + } + err = yaml.Unmarshal(stateBytes, &util.state) + if err != nil { + return err + } + return err +} + +func (util *Util) SaveState() error { + var err error + + file, err := os.OpenFile(util.sfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + if err != nil { + return err + } + defer file.Close() + util.state.UpdatedAt = time.Now().Format(time.RFC3339) + if util.state.CreatedAt == "" { + util.state.CreatedAt = util.state.UpdatedAt + } + stateBytes, err := yaml.Marshal(util.state) + if err != nil { + return err + } + _, err = file.Write(stateBytes) + if err != nil { + return err + } + return err +} diff --git a/cmd/mbaseadmin/account/create.go b/cmd/mbaseadmin/account/create.go new file mode 100644 index 0000000..70c7a4c --- /dev/null +++ b/cmd/mbaseadmin/account/create.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) CreateAccount(cmd *cobra.Command, args []string) { + //util.createAccountParams.Filename = args[0] + res, err := util.createAccount(util.createAccountParams) + printResponse(res, err) +} + +type createAccountParams struct{} +type createAccountResult struct{} + +func (util *Util) createAccount(params createAccountParams) (createAccountResult, error) { + var err error + res := createAccountResult{} + return res, err +} diff --git a/cmd/mbaseadmin/account/delete.go b/cmd/mbaseadmin/account/delete.go new file mode 100644 index 0000000..8d77b1d --- /dev/null +++ b/cmd/mbaseadmin/account/delete.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) DeleteAccount(cmd *cobra.Command, args []string) { + //util.deleteAccountParams.Filename = args[0] + res, err := util.deleteAccount(util.deleteAccountParams) + printResponse(res, err) +} + +type deleteAccountParams struct{} +type deleteAccountResult struct{} + +func (util *Util) deleteAccount(params deleteAccountParams) (deleteAccountResult, error) { + var err error + res := deleteAccountResult{} + return res, err +} diff --git a/cmd/mbaseadmin/account/list.go b/cmd/mbaseadmin/account/list.go new file mode 100644 index 0000000..7b603dc --- /dev/null +++ b/cmd/mbaseadmin/account/list.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) ListAccounts(cmd *cobra.Command, args []string) { + //util.listAccountsParams.Filename = args[0] + res, err := util.listAccounts(util.listAccountsParams) + printResponse(res, err) +} + +type listAccountsParams struct{} +type listAccountsResult struct{} + +func (util *Util) listAccounts(params listAccountsParams) (listAccountsResult, error) { + var err error + res := listAccountsResult{} + return res, err +} diff --git a/cmd/mbaseadmin/account/printr.go b/cmd/mbaseadmin/account/printr.go new file mode 100644 index 0000000..48d8e9e --- /dev/null +++ b/cmd/mbaseadmin/account/printr.go @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "fmt" + + "sigs.k8s.io/yaml" +) + +func printResponse(res any, err error) { + type Response struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` + } + resp := Response{} + if err != nil { + resp.Error = true + resp.Message = err.Error() + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Printf("---\n%s\n", string(respBytes)) +} diff --git a/cmd/mbaseadmin/account/update.go b/cmd/mbaseadmin/account/update.go new file mode 100644 index 0000000..ab0ad0d --- /dev/null +++ b/cmd/mbaseadmin/account/update.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) UpdateAccount(cmd *cobra.Command, args []string) { + //util.updateAccountParams.Filename = args[0] + res, err := util.updateAccount(util.updateAccountParams) + printResponse(res, err) +} + +type updateAccountParams struct{} +type updateAccountResult struct{} + +func (util *Util) updateAccount(params updateAccountParams) (updateAccountResult, error) { + var err error + res := updateAccountResult{} + return res, err +} diff --git a/cmd/mbaseadmin/account/util.go b/cmd/mbaseadmin/account/util.go new file mode 100644 index 0000000..f7280e2 --- /dev/null +++ b/cmd/mbaseadmin/account/util.go @@ -0,0 +1,68 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +type Util struct { + rootCmd *cobra.Command + createAccountParams createAccountParams + listAccountsParams listAccountsParams + updateAccountParams updateAccountParams + deleteAccountParams deleteAccountParams +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) BuildCmds() *cobra.Command { + rootCmd := &cobra.Command{ + Use: "account", + Short: "\nAccount operations", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + var createAccountCmd = &cobra.Command{ + Use: "create name password ", + Short: "Create account", + Args: cobra.ExactArgs(2), + Run: util.CreateAccount, + } + rootCmd.AddCommand(createAccountCmd) + + var listAccountsCmd = &cobra.Command{ + Use: "list", + Short: "List accounts", + Run: util.ListAccounts, + } + rootCmd.AddCommand(listAccountsCmd) + + var updateAccountsCmd = &cobra.Command{ + Use: "update name|id", + Short: "Update account", + Args: cobra.ExactArgs(1), + Run: util.UpdateAccount, + } + rootCmd.AddCommand(updateAccountsCmd) + + var deleteAccountCmd = &cobra.Command{ + Use: "delete name|id", + Short: "Delete account", + Args: cobra.ExactArgs(1), + Run: util.DeleteAccount, + } + rootCmd.AddCommand(deleteAccountCmd) + + util.rootCmd = rootCmd + return util.rootCmd +} + diff --git a/cmd/mbaseadmin/grant/attic/account.gox b/cmd/mbaseadmin/grant/attic/account.gox new file mode 100644 index 0000000..5b2cd5e --- /dev/null +++ b/cmd/mbaseadmin/grant/attic/account.gox @@ -0,0 +1,63 @@ +package main + +import ( + "context" + + "mbase/pkg/mbctl" +) + +func (util *Util) CreateAccount(ctx context.Context, operID string) (*mbctl.CreateAccountResult, error) { + var err error + res := &mbctl.CreateAccountResult{} + + params := &mbctl.CreateAccountParams{ + Username: util.username, + Password: util.password, + } + res, err = util.lg.CreateAccount(ctx, operID, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) DeleteAccount(ctx context.Context, operID string) (*mbctl.DeleteAccountResult, error) { + var err error + res := &mbctl.DeleteAccountResult{} + params := &mbctl.DeleteAccountParams{ + Username: util.username, + AccountID: util.accountID, + } + res, err = util.lg.DeleteAccount(ctx, operID, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) ListAccounts(ctx context.Context, operID string) (*mbctl.ListAccountsResult, error) { + var err error + res := &mbctl.ListAccountsResult{} + params := &mbctl.ListAccountsParams{} + res, err = util.lg.ListAccounts(ctx, operID, params) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) UpdateAccount(ctx context.Context, operID string) (*mbctl.UpdateAccountResult, error) { + var err error + res := &mbctl.UpdateAccountResult{} + params := &mbctl.UpdateAccountParams{ + Username: util.username, + AccountID: util.accountID, + NewUsername: util.newUsername, + NewPassword: util.newPassword, + } + res, err = util.lg.UpdateAccount(ctx, operID, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbaseadmin/grant/attic/grant.gox b/cmd/mbaseadmin/grant/attic/grant.gox new file mode 100644 index 0000000..abf9ad5 --- /dev/null +++ b/cmd/mbaseadmin/grant/attic/grant.gox @@ -0,0 +1,40 @@ +package main + +import ( + "context" + + "mbase/pkg/mbctl" +) + +func (util *Util) SetGrant(ctx context.Context, operID string) (*mbctl.SetGrantResult, error) { + var err error + res := &mbctl.SetGrantResult{} + params := &mbctl.SetGrantParams{ + Username: util.username, + AccountID: util.accountID, + Operation: util.operation, + } + res, err = util.lg.SetGrant(ctx, operID, params) + if err != nil { + return res, err + } + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) DeleteGrant(ctx context.Context, operID string) (*mbctl.DeleteGrantResult, error) { + var err error + res := &mbctl.DeleteGrantResult{} + params := &mbctl.DeleteGrantParams{ + Username: util.username, + AccountID: util.accountID, + Operation: util.operation, + } + res, err = util.lg.DeleteGrant(ctx, operID, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbaseadmin/grant/attic/main.gox b/cmd/mbaseadmin/grant/attic/main.gox new file mode 100644 index 0000000..f6ae115 --- /dev/null +++ b/cmd/mbaseadmin/grant/attic/main.gox @@ -0,0 +1,467 @@ +/* + * Copyright 2024 Oleg Borodin + */ + +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "time" + + "mbase/app/config" + "mbase/app/maindb" + "mbase/pkg/descr" + "mbase/app/logic" + + "sigs.k8s.io/yaml" +) + +const ( + rcFilename = ".certmanager.yaml" + + helpCmd = "help" + + createAccountCmd = "createAccount" + updateAccountCmd = "updateAccount" + deleteAccountCmd = "deleteAccount" + listAccountsCmd = "listAccounts" + + setGrantCmd = "setGrant" + deleteGrantCmd = "deleteGrant" + + initDatabaseCmd = "initDatabase" + seedAccountCmd = "seedAccount" +) + +func main() { + var err error + util := NewUtil() + err = util.Build() + if err != nil { + fmt.Printf("Build error: %v\n", err) + os.Exit(1) + } + err = util.Exec() + if err != nil { + fmt.Printf("Exec error: %v\n", err) + os.Exit(1) + } + os.Exit(0) +} + +type Util struct { + subCmd string + cmdTimeout int64 + + conf *config.Config + lg *logic.Logic + db *maindb.Database + state descr.Server + sfile string + + accessUsername string + accessPassword string + accountID int64 + username string + password string + disable bool + newUsername string + newPassword string + operation string + quiet bool +} + +func NewUtil() *Util { + var util Util + util.cmdTimeout = 120 + return &util +} + +func (util *Util) GetOpt() error { + var err error + + exeName := filepath.Base(os.Args[0]) + + flag.Int64Var(&util.cmdTimeout, "timeout", util.cmdTimeout, "command execution timeout") + flag.StringVar(&util.accessUsername, "user", util.accessUsername, "access login") + flag.StringVar(&util.accessPassword, "pass", util.accessPassword, "access password") + flag.BoolVar(&util.quiet, "quiet", util.quiet, "don't print result") + + help := func() { + fmt.Println("") + fmt.Printf("Usage: %s [option] command [command option]\n", exeName) + fmt.Printf("\n") + fmt.Printf(" %s, %s, %s, %s,\n", + createAccountCmd, + deleteAccountCmd, + listAccountsCmd, + updateAccountCmd) + fmt.Printf(" %s, %s\n", + setGrantCmd, + deleteGrantCmd) + fmt.Printf(" %s, %s\n", + initDatabaseCmd, + seedAccountCmd) + + fmt.Printf("\n") + fmt.Printf("Global options:\n") + flag.PrintDefaults() + fmt.Printf("\n") + } + flag.Usage = help + flag.Parse() + + args := flag.Args() + + var subCmd string + var subArgs []string + if len(args) > 0 { + subCmd = args[0] + subArgs = args[1:] + } + + util.subCmd = subCmd + + switch subCmd { + case helpCmd: + help() + return errors.New("Unknown command") + + case createAccountCmd: + flagSet := flag.NewFlagSet(createAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.StringVar(&util.password, "password", util.password, "user password") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteAccountCmd: + flagSet := flag.NewFlagSet(deleteAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case listAccountsCmd: + flagSet := flag.NewFlagSet(listAccountsCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case updateAccountCmd: + flagSet := flag.NewFlagSet(updateAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.StringVar(&util.newUsername, "newUsername", util.newUsername, "new user name") + flagSet.StringVar(&util.newPassword, "newPassword", util.newPassword, "new user password") + flagSet.BoolVar(&util.disable, "disable", util.disable, "disable account") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case setGrantCmd: + flagSet := flag.NewFlagSet(setGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteGrantCmd: + flagSet := flag.NewFlagSet(deleteGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case initDatabaseCmd: + flagSet := flag.NewFlagSet(initDatabaseCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + case seedAccountCmd: + flagSet := flag.NewFlagSet(seedAccountCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + default: + help() + return errors.New("Unknown command") + } + return err +} + +func (util *Util) Build() error { + var err error + + util.conf = config.NewConfig() + err = util.conf.ReadFile() + if err != nil { + return err + } + err = util.conf.ReadEnv() + if err != nil { + return err + } + + util.sfile = filepath.Join(util.conf.DataDir, "certmanager.yaml") + + db, err := maindb.NewDatabase(util.conf.DataDir) + if err != nil { + return err + } + err = db.OpenDatabase() + if err != nil { + return err + } + util.db = db + logicConfig := &logic.LogicConfig{ + Database: util.db, + } + util.lg, err = logic.NewLogic(logicConfig) + if err != nil { + return err + } + return err +} + +type Response struct { + Command string `json:"command" yaml:"command"` + Args []string `json:"args" yaml:"args"` + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` +} + +func (util *Util) Exec() error { + var err error + err = util.GetOpt() + if err != nil { + return err + } + + var timeout = time.Duration(util.cmdTimeout) * time.Second + ctx, close := context.WithTimeout(context.Background(), timeout) + defer close() + + var res any + + switch util.subCmd { + case initDatabaseCmd: + res, err = util.InitDatabase(ctx) + case seedAccountCmd: + res, err = util.SeedAccount(ctx) + default: + authOk, operID, localErr := util.lg.ValidateAcount(ctx, util.accessUsername, util.accessPassword) + if err != nil { + err = localErr + goto exit + } + if !authOk { + err = fmt.Errorf("Incorrect username or password") + goto exit + } + switch util.subCmd { + case createAccountCmd: + res, err = util.CreateAccount(ctx, operID) + case updateAccountCmd: + res, err = util.UpdateAccount(ctx, operID) + case listAccountsCmd: + res, err = util.ListAccounts(ctx, operID) + case deleteAccountCmd: + res, err = util.DeleteAccount(ctx, operID) + case setGrantCmd: + res, err = util.SetGrant(ctx, operID) + case deleteGrantCmd: + res, err = util.DeleteGrant(ctx, operID) + default: + err = errors.New("Unknown cli command") + } + } + +exit: + var resp Response + resp.Command = util.subCmd + resp.Args = os.Args + if err != nil { + resp.Error = true + resp.Message = fmt.Sprintf("%v", err) + } else { + resp.Result = res + } + + if !resp.Error && !util.quiet { + respBytes, _ := yaml.Marshal(resp) + fmt.Println(string(respBytes)) + } + return err +} + +type InitDatabaseRes struct{} + +func (util *Util) InitDatabase(ctx context.Context) (InitDatabaseRes, error) { + res := InitDatabaseRes{} + // Initialize database + + // Load state + err := util.LoadState() + if err != nil { + return res, err + } + if !util.state.DatabaseInitialized { + if util.db == nil { + err = fmt.Errorf("Nil db object") + return res, err + } + err := util.db.InitDatabase() + if err != nil { + return res, err + } + util.state.DatabaseInitialized = true + err = util.SaveState() + if err != nil { + return res, err + } + + } + return res, err +} + +type SeedAccountRes struct{} + +func (util *Util) SeedAccount(ctx context.Context) (SeedAccountRes, error) { + // Seed accounts + res := SeedAccountRes{} + _, err := util.lg.SeedAccount(ctx) + if err != nil { + return res, err + } + return res, err +} + +func (util *Util) LoadState() error { + var err error + _, err = os.Stat(util.sfile) + if os.IsNotExist(err) { + err = nil + return err + } + file, err := os.Open(util.sfile) + if err != nil { + return err + } + defer file.Close() + stateBytes, err := ioutil.ReadAll(file) + if err != nil { + return err + } + err = yaml.Unmarshal(stateBytes, &util.state) + if err != nil { + return err + } + return err +} + +func (util *Util) SaveState() error { + var err error + + file, err := os.OpenFile(util.sfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) + if err != nil { + return err + } + defer file.Close() + util.state.UpdatedAt = time.Now().Format(time.RFC3339) + if util.state.CreatedAt == "" { + util.state.CreatedAt = util.state.UpdatedAt + } + stateBytes, err := yaml.Marshal(util.state) + if err != nil { + return err + } + _, err = file.Write(stateBytes) + if err != nil { + return err + } + return err +} diff --git a/cmd/mbaseadmin/grant/create.go b/cmd/mbaseadmin/grant/create.go new file mode 100644 index 0000000..bc3445c --- /dev/null +++ b/cmd/mbaseadmin/grant/create.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) CreateGrant(cmd *cobra.Command, args []string) { + //util.createGrantParams.Filename = args[0] + res, err := util.createGrant(util.createGrantParams) + printResponse(res, err) +} + +type createGrantParams struct{} +type createGrantResult struct{} + +func (util *Util) createGrant(params createGrantParams) (createGrantResult, error) { + var err error + res := createGrantResult{} + return res, err +} diff --git a/cmd/mbaseadmin/grant/delete.go b/cmd/mbaseadmin/grant/delete.go new file mode 100644 index 0000000..f4a5db3 --- /dev/null +++ b/cmd/mbaseadmin/grant/delete.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) DeleteGrant(cmd *cobra.Command, args []string) { + //util.deleteGrantParams.Filename = args[0] + res, err := util.deleteGrant(util.deleteGrantParams) + printResponse(res, err) +} + +type deleteGrantParams struct{} +type deleteGrantResult struct{} + +func (util *Util) deleteGrant(params deleteGrantParams) (deleteGrantResult, error) { + var err error + res := deleteGrantResult{} + return res, err +} diff --git a/cmd/mbaseadmin/grant/printr.go b/cmd/mbaseadmin/grant/printr.go new file mode 100644 index 0000000..48d8e9e --- /dev/null +++ b/cmd/mbaseadmin/grant/printr.go @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "fmt" + + "sigs.k8s.io/yaml" +) + +func printResponse(res any, err error) { + type Response struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` + } + resp := Response{} + if err != nil { + resp.Error = true + resp.Message = err.Error() + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Printf("---\n%s\n", string(respBytes)) +} diff --git a/cmd/mbaseadmin/grant/util.go b/cmd/mbaseadmin/grant/util.go new file mode 100644 index 0000000..62cec53 --- /dev/null +++ b/cmd/mbaseadmin/grant/util.go @@ -0,0 +1,51 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package grant + +import ( + "github.com/spf13/cobra" +) + +type Util struct { + rootCmd *cobra.Command + createGrantParams createGrantParams + deleteGrantParams deleteGrantParams +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) BuildCmds() *cobra.Command { + rootCmd := &cobra.Command{ + Use: "grant", + Short: "\nGrant operations", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + var createGrantCmd = &cobra.Command{ + Use: "create name|id password", + Short: "Create grant", + Args: cobra.ExactArgs(2), + Run: util.CreateGrant, + } + rootCmd.AddCommand(createGrantCmd) + + var deleteGrantCmd = &cobra.Command{ + Use: "delete name|id grant", + Short: "Delete grant", + Args: cobra.ExactArgs(1), + Run: util.DeleteGrant, + } + rootCmd.AddCommand(deleteGrantCmd) + + util.rootCmd = rootCmd + return util.rootCmd +} + diff --git a/cmd/mbaseadmin/main.go b/cmd/mbaseadmin/main.go index 7eefbcd..eaaf76d 100644 --- a/cmd/mbaseadmin/main.go +++ b/cmd/mbaseadmin/main.go @@ -1,42 +1,10 @@ /* - * Copyright 2024 Oleg Borodin + * Copyright 2026 Oleg Borodin */ - package main import ( - "context" - "errors" - "flag" - "fmt" - "io/ioutil" "os" - "path/filepath" - "time" - - "mbase/app/config" - "mbase/app/maindb" - "mbase/app/descr" - "mbase/app/logic" - - "sigs.k8s.io/yaml" -) - -const ( - rcFilename = ".certmanager.yaml" - - helpCmd = "help" - - createAccountCmd = "createAccount" - updateAccountCmd = "updateAccount" - deleteAccountCmd = "deleteAccount" - listAccountsCmd = "listAccounts" - - setGrantCmd = "setGrant" - deleteGrantCmd = "deleteGrant" - - initDatabaseCmd = "initDatabase" - seedAccountCmd = "seedAccount" ) func main() { @@ -44,424 +12,10 @@ func main() { util := NewUtil() err = util.Build() if err != nil { - fmt.Printf("Build error: %v\n", err) os.Exit(1) } - err = util.Exec() + err = util.Exec(os.Args[1:]) if err != nil { - fmt.Printf("Exec error: %v\n", err) os.Exit(1) } - os.Exit(0) -} - -type Util struct { - subCmd string - cmdTimeout int64 - - conf *config.Config - lg *logic.Logic - db *maindb.Database - state descr.Server - sfile string - - accessUsername string - accessPassword string - accountID int64 - username string - password string - disable bool - newUsername string - newPassword string - operation string - quiet bool -} - -func NewUtil() *Util { - var util Util - util.cmdTimeout = 120 - return &util -} - -func (util *Util) GetOpt() error { - var err error - - exeName := filepath.Base(os.Args[0]) - - flag.Int64Var(&util.cmdTimeout, "timeout", util.cmdTimeout, "command execution timeout") - flag.StringVar(&util.accessUsername, "user", util.accessUsername, "access login") - flag.StringVar(&util.accessPassword, "pass", util.accessPassword, "access password") - flag.BoolVar(&util.quiet, "quiet", util.quiet, "don't print result") - - help := func() { - fmt.Println("") - fmt.Printf("Usage: %s [option] command [command option]\n", exeName) - fmt.Printf("\n") - fmt.Printf(" %s, %s, %s, %s,\n", - createAccountCmd, - deleteAccountCmd, - listAccountsCmd, - updateAccountCmd) - fmt.Printf(" %s, %s\n", - setGrantCmd, - deleteGrantCmd) - fmt.Printf(" %s, %s\n", - initDatabaseCmd, - seedAccountCmd) - - fmt.Printf("\n") - fmt.Printf("Global options:\n") - flag.PrintDefaults() - fmt.Printf("\n") - } - flag.Usage = help - flag.Parse() - - args := flag.Args() - - var subCmd string - var subArgs []string - if len(args) > 0 { - subCmd = args[0] - subArgs = args[1:] - } - - util.subCmd = subCmd - - switch subCmd { - case helpCmd: - help() - return errors.New("Unknown command") - - case createAccountCmd: - flagSet := flag.NewFlagSet(createAccountCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.StringVar(&util.password, "password", util.password, "user password") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case deleteAccountCmd: - flagSet := flag.NewFlagSet(deleteAccountCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case listAccountsCmd: - flagSet := flag.NewFlagSet(listAccountsCmd, flag.ExitOnError) - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case updateAccountCmd: - flagSet := flag.NewFlagSet(updateAccountCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - - flagSet.StringVar(&util.newUsername, "newUsername", util.newUsername, "new user name") - flagSet.StringVar(&util.newPassword, "newPassword", util.newPassword, "new user password") - flagSet.BoolVar(&util.disable, "disable", util.disable, "disable account") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case setGrantCmd: - flagSet := flag.NewFlagSet(setGrantCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case deleteGrantCmd: - flagSet := flag.NewFlagSet(deleteGrantCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case initDatabaseCmd: - flagSet := flag.NewFlagSet(initDatabaseCmd, flag.ExitOnError) - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - case seedAccountCmd: - flagSet := flag.NewFlagSet(seedAccountCmd, flag.ExitOnError) - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - default: - help() - return errors.New("Unknown command") - } - return err -} - -func (util *Util) Build() error { - var err error - - util.conf = config.NewConfig() - err = util.conf.ReadFile() - if err != nil { - return err - } - err = util.conf.ReadEnv() - if err != nil { - return err - } - - util.sfile = filepath.Join(util.conf.DataDir, "certmanager.yaml") - - db, err := maindb.NewDatabase(util.conf.DataDir) - if err != nil { - return err - } - err = db.OpenDatabase() - if err != nil { - return err - } - util.db = db - logicConfig := &logic.LogicConfig{ - Database: util.db, - } - util.lg, err = logic.NewLogic(logicConfig) - if err != nil { - return err - } - return err -} - -type Response struct { - Command string `json:"command" yaml:"command"` - Args []string `json:"args" yaml:"args"` - Error bool `json:"error" yaml:"error"` - Message string `json:"message,omitempty" yaml:"message,omitempty"` - Result any `json:"result,omitempty" yaml:"result,omitempty"` -} - -func (util *Util) Exec() error { - var err error - err = util.GetOpt() - if err != nil { - return err - } - - var timeout = time.Duration(util.cmdTimeout) * time.Second - ctx, close := context.WithTimeout(context.Background(), timeout) - defer close() - - var res any - - switch util.subCmd { - case initDatabaseCmd: - res, err = util.InitDatabase(ctx) - case seedAccountCmd: - res, err = util.SeedAccount(ctx) - default: - authOk, operID, localErr := util.lg.ValidateAcount(ctx, util.accessUsername, util.accessPassword) - if err != nil { - err = localErr - goto exit - } - if !authOk { - err = fmt.Errorf("Incorrect username or password") - goto exit - } - switch util.subCmd { - case createAccountCmd: - res, err = util.CreateAccount(ctx, operID) - case updateAccountCmd: - res, err = util.UpdateAccount(ctx, operID) - case listAccountsCmd: - res, err = util.ListAccounts(ctx, operID) - case deleteAccountCmd: - res, err = util.DeleteAccount(ctx, operID) - case setGrantCmd: - res, err = util.SetGrant(ctx, operID) - case deleteGrantCmd: - res, err = util.DeleteGrant(ctx, operID) - default: - err = errors.New("Unknown cli command") - } - } - -exit: - var resp Response - resp.Command = util.subCmd - resp.Args = os.Args - if err != nil { - resp.Error = true - resp.Message = fmt.Sprintf("%v", err) - } else { - resp.Result = res - } - - if !resp.Error && !util.quiet { - respBytes, _ := yaml.Marshal(resp) - fmt.Println(string(respBytes)) - } - return err -} - -type InitDatabaseRes struct{} - -func (util *Util) InitDatabase(ctx context.Context) (InitDatabaseRes, error) { - res := InitDatabaseRes{} - // Initialize database - - // Load state - err := util.LoadState() - if err != nil { - return res, err - } - if !util.state.DatabaseInitialized { - if util.db == nil { - err = fmt.Errorf("Nil db object") - return res, err - } - err := util.db.InitDatabase() - if err != nil { - return res, err - } - util.state.DatabaseInitialized = true - err = util.SaveState() - if err != nil { - return res, err - } - - } - return res, err -} - -type SeedAccountRes struct{} - -func (util *Util) SeedAccount(ctx context.Context) (SeedAccountRes, error) { - // Seed accounts - res := SeedAccountRes{} - _, err := util.lg.SeedAccount(ctx) - if err != nil { - return res, err - } - return res, err -} - -func (util *Util) LoadState() error { - var err error - _, err = os.Stat(util.sfile) - if os.IsNotExist(err) { - err = nil - return err - } - file, err := os.Open(util.sfile) - if err != nil { - return err - } - defer file.Close() - stateBytes, err := ioutil.ReadAll(file) - if err != nil { - return err - } - err = yaml.Unmarshal(stateBytes, &util.state) - if err != nil { - return err - } - return err -} - -func (util *Util) SaveState() error { - var err error - - file, err := os.OpenFile(util.sfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0640) - if err != nil { - return err - } - defer file.Close() - util.state.UpdatedAt = time.Now().Format(time.RFC3339) - if util.state.CreatedAt == "" { - util.state.CreatedAt = util.state.UpdatedAt - } - stateBytes, err := yaml.Marshal(util.state) - if err != nil { - return err - } - _, err = file.Write(stateBytes) - if err != nil { - return err - } - return err } diff --git a/cmd/mbaseadmin/util.go b/cmd/mbaseadmin/util.go new file mode 100644 index 0000000..5d9fed9 --- /dev/null +++ b/cmd/mbaseadmin/util.go @@ -0,0 +1,49 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package main + +import ( + "os" + "path/filepath" + + "mbase/cmd/mbaseadmin/account" + + "github.com/spf13/cobra" +) + +type Util struct { + rootCmd *cobra.Command +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) Build() error { + var err error + execName := filepath.Base(os.Args[0]) + rootCmd := &cobra.Command{ + Use: execName, + Short: "\nAccount operations", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + accountUtil := account.NewUtil() + rootCmd.AddCommand(accountUtil.BuildCmds()) + + util.rootCmd = rootCmd + return err +} + +func (util *Util) Exec(args []string) error { + var err error + util.rootCmd.SetArgs(args) + err = util.rootCmd.Execute() + return err +} diff --git a/cmd/mbasectl/account/create.go b/cmd/mbasectl/account/create.go new file mode 100644 index 0000000..70c7a4c --- /dev/null +++ b/cmd/mbasectl/account/create.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) CreateAccount(cmd *cobra.Command, args []string) { + //util.createAccountParams.Filename = args[0] + res, err := util.createAccount(util.createAccountParams) + printResponse(res, err) +} + +type createAccountParams struct{} +type createAccountResult struct{} + +func (util *Util) createAccount(params createAccountParams) (createAccountResult, error) { + var err error + res := createAccountResult{} + return res, err +} diff --git a/cmd/mbasectl/account/delete.go b/cmd/mbasectl/account/delete.go new file mode 100644 index 0000000..8d77b1d --- /dev/null +++ b/cmd/mbasectl/account/delete.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) DeleteAccount(cmd *cobra.Command, args []string) { + //util.deleteAccountParams.Filename = args[0] + res, err := util.deleteAccount(util.deleteAccountParams) + printResponse(res, err) +} + +type deleteAccountParams struct{} +type deleteAccountResult struct{} + +func (util *Util) deleteAccount(params deleteAccountParams) (deleteAccountResult, error) { + var err error + res := deleteAccountResult{} + return res, err +} diff --git a/cmd/mbasectl/account/list.go b/cmd/mbasectl/account/list.go new file mode 100644 index 0000000..7b603dc --- /dev/null +++ b/cmd/mbasectl/account/list.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) ListAccounts(cmd *cobra.Command, args []string) { + //util.listAccountsParams.Filename = args[0] + res, err := util.listAccounts(util.listAccountsParams) + printResponse(res, err) +} + +type listAccountsParams struct{} +type listAccountsResult struct{} + +func (util *Util) listAccounts(params listAccountsParams) (listAccountsResult, error) { + var err error + res := listAccountsResult{} + return res, err +} diff --git a/cmd/mbasectl/account/printr.go b/cmd/mbasectl/account/printr.go new file mode 100644 index 0000000..48d8e9e --- /dev/null +++ b/cmd/mbasectl/account/printr.go @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "fmt" + + "sigs.k8s.io/yaml" +) + +func printResponse(res any, err error) { + type Response struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` + } + resp := Response{} + if err != nil { + resp.Error = true + resp.Message = err.Error() + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Printf("---\n%s\n", string(respBytes)) +} diff --git a/cmd/mbasectl/account/update.go b/cmd/mbasectl/account/update.go new file mode 100644 index 0000000..ab0ad0d --- /dev/null +++ b/cmd/mbasectl/account/update.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) UpdateAccount(cmd *cobra.Command, args []string) { + //util.updateAccountParams.Filename = args[0] + res, err := util.updateAccount(util.updateAccountParams) + printResponse(res, err) +} + +type updateAccountParams struct{} +type updateAccountResult struct{} + +func (util *Util) updateAccount(params updateAccountParams) (updateAccountResult, error) { + var err error + res := updateAccountResult{} + return res, err +} diff --git a/cmd/mbasectl/account/util.go b/cmd/mbasectl/account/util.go new file mode 100644 index 0000000..f7280e2 --- /dev/null +++ b/cmd/mbasectl/account/util.go @@ -0,0 +1,68 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +type Util struct { + rootCmd *cobra.Command + createAccountParams createAccountParams + listAccountsParams listAccountsParams + updateAccountParams updateAccountParams + deleteAccountParams deleteAccountParams +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) BuildCmds() *cobra.Command { + rootCmd := &cobra.Command{ + Use: "account", + Short: "\nAccount operations", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + var createAccountCmd = &cobra.Command{ + Use: "create name password ", + Short: "Create account", + Args: cobra.ExactArgs(2), + Run: util.CreateAccount, + } + rootCmd.AddCommand(createAccountCmd) + + var listAccountsCmd = &cobra.Command{ + Use: "list", + Short: "List accounts", + Run: util.ListAccounts, + } + rootCmd.AddCommand(listAccountsCmd) + + var updateAccountsCmd = &cobra.Command{ + Use: "update name|id", + Short: "Update account", + Args: cobra.ExactArgs(1), + Run: util.UpdateAccount, + } + rootCmd.AddCommand(updateAccountsCmd) + + var deleteAccountCmd = &cobra.Command{ + Use: "delete name|id", + Short: "Delete account", + Args: cobra.ExactArgs(1), + Run: util.DeleteAccount, + } + rootCmd.AddCommand(deleteAccountCmd) + + util.rootCmd = rootCmd + return util.rootCmd +} + diff --git a/cmd/mbasectl/account.go b/cmd/mbasectl/attic/account.go similarity index 100% rename from cmd/mbasectl/account.go rename to cmd/mbasectl/attic/account.go diff --git a/cmd/mbasectl/dump.go b/cmd/mbasectl/attic/dump.go similarity index 100% rename from cmd/mbasectl/dump.go rename to cmd/mbasectl/attic/dump.go diff --git a/cmd/mbasectl/grant.go b/cmd/mbasectl/attic/grant.go similarity index 100% rename from cmd/mbasectl/grant.go rename to cmd/mbasectl/attic/grant.go diff --git a/cmd/mbasectl/attic/main.go b/cmd/mbasectl/attic/main.go new file mode 100644 index 0000000..a6da0e9 --- /dev/null +++ b/cmd/mbasectl/attic/main.go @@ -0,0 +1,398 @@ +/* + * Copyright 2024 Oleg Borodin + */ + +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "os" + "os/user" + "path/filepath" + "time" + + "mbase/pkg/client" + "mbase/pkg/mbctl" + + "sigs.k8s.io/yaml" +) + +const ( + defaultHostname = "localhost" + rcFilename = ".certmanager.yaml" + defaultPort uint32 = client.DefaultPort + + getHelloCmd = "getHello" + helpCmd = "help" + + createAccountCmd = "createAccount" + updateAccountCmd = "updateAccount" + deleteAccountCmd = "deleteAccount" + listAccountsCmd = "listAccounts" + + setGrantCmd = "setGrant" + deleteGrantCmd = "deleteGrant" + + getDumpCmd = "getDump" + restoreDumpCmd = "restoreDump" +) + +func main() { + var err error + util := NewUtil() + err = util.Exec() + if err != nil { + os.Exit(1) + } + os.Exit(0) +} + +type Util struct { + subCmd string + cmdTimeout int64 + access client.Access + cont *mbctl.ControlClient + + caFilenamesList string + certFilename string + keyFilename string + issuerOrganizationName string + issuerOrganizationalUnitName string + issuerCommonName string + issuerID int64 + issuerName string + signerID int64 + signerName string + serviceOrganizationName string + serviceOrganizationalUnitName string + serviceCommonName string + hostnameList string + ipAdressesList string + serviceID int64 + serviceName string + encodingKey string + + accountID int64 + username string + password string + disable bool + newUsername string + newPassword string + operation string + filename string + deleteAllRecords bool +} + +func NewUtil() *Util { + var util Util + util.cmdTimeout = 120 + util.access = client.Access{ + Hostname: defaultHostname, + Port: defaultPort, + Username: "certmanager", + Password: "certmanager", + } + return &util +} + +func (util *Util) GetOpt() error { + var err error + + homeDir := os.Getenv("HOME") + if homeDir == "" { + currUsr, err := user.Current() + if err == nil { + homeDir = currUsr.HomeDir + } + } + if homeDir != "" { + confPath := filepath.Join(homeDir, rcFilename) + confData, err := os.ReadFile(confPath) + if err == nil && len(confData) > 0 { + yaml.Unmarshal(confData, &util.access) + } + } + exeName := filepath.Base(os.Args[0]) + + servicePort := int64(defaultPort) + flag.Int64Var(&util.cmdTimeout, "timeout", util.cmdTimeout, "command execution timeout") + flag.StringVar(&util.access.Hostname, "host", util.access.Hostname, "service hostname") + flag.Int64Var(&servicePort, "port", servicePort, "service port") + flag.StringVar(&util.access.Username, "user", util.access.Username, "access login") + flag.StringVar(&util.access.Password, "pass", util.access.Password, "access password") + + util.access.Port = uint32(servicePort) + + help := func() { + fmt.Println("") + fmt.Printf("Usage: %s [option] command [command option]\n", exeName) + fmt.Printf("\n") + fmt.Printf("Command list: help, %s\n", getHelloCmd) + fmt.Printf(" %s, %s, %s, %s,\n", + createAccountCmd, + deleteAccountCmd, + listAccountsCmd, + updateAccountCmd) + fmt.Printf(" %s, %s\n", + setGrantCmd, + deleteGrantCmd) + fmt.Printf(" %s, %s\n", + getDumpCmd, + restoreDumpCmd) + + fmt.Printf("\n") + fmt.Printf("Global options:\n") + flag.PrintDefaults() + fmt.Printf("\n") + } + flag.Usage = help + flag.Parse() + + args := flag.Args() + + var subCmd string + var subArgs []string + if len(args) > 0 { + subCmd = args[0] + subArgs = args[1:] + } + + switch subCmd { + case helpCmd: + help() + return errors.New("Unknown command") + case getHelloCmd: + flagSet := flag.NewFlagSet(getHelloCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + flagSet.Parse(subArgs) + + case createAccountCmd: + flagSet := flag.NewFlagSet(createAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.StringVar(&util.password, "password", util.password, "user password") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteAccountCmd: + flagSet := flag.NewFlagSet(deleteAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case listAccountsCmd: + flagSet := flag.NewFlagSet(listAccountsCmd, flag.ExitOnError) + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case updateAccountCmd: + flagSet := flag.NewFlagSet(updateAccountCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + + flagSet.StringVar(&util.newUsername, "newUsername", util.newUsername, "new user name") + flagSet.StringVar(&util.newPassword, "newPassword", util.newPassword, "new user password") + flagSet.BoolVar(&util.disable, "disable", util.disable, "disable account") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case setGrantCmd: + flagSet := flag.NewFlagSet(setGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case deleteGrantCmd: + flagSet := flag.NewFlagSet(deleteGrantCmd, flag.ExitOnError) + + flagSet.StringVar(&util.username, "username", util.username, "user name") + flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") + flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case getDumpCmd: + flagSet := flag.NewFlagSet(getDumpCmd, flag.ExitOnError) + flagSet.StringVar(&util.filename, "file", util.filename, "dump file name") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + case restoreDumpCmd: + flagSet := flag.NewFlagSet(restoreDumpCmd, flag.ExitOnError) + flagSet.StringVar(&util.filename, "file", util.filename, "dump file name") + + flagSet.Usage = func() { + fmt.Printf("\n") + fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) + fmt.Printf("\n") + fmt.Printf("The command options: none\n") + flagSet.PrintDefaults() + fmt.Printf("\n") + } + flagSet.Parse(subArgs) + util.subCmd = subCmd + + default: + help() + return errors.New("Unknown command") + } + return err +} + +type Response struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` +} + +func (util *Util) Exec() error { + var err error + err = util.GetOpt() + if err != nil { + return err + } + + var timeout = time.Duration(util.cmdTimeout) * time.Second + ctx, close := context.WithTimeout(context.Background(), timeout) + defer close() + + var res any + switch util.subCmd { + case getHelloCmd: + res, err = util.GetHello(ctx) + + case createAccountCmd: + res, err = util.CreateAccount(ctx) + case updateAccountCmd: + res, err = util.UpdateAccount(ctx) + case listAccountsCmd: + res, err = util.ListAccounts(ctx) + case deleteAccountCmd: + res, err = util.DeleteAccount(ctx) + + case setGrantCmd: + res, err = util.SetGrant(ctx) + case deleteGrantCmd: + res, err = util.DeleteGrant(ctx) + + case getDumpCmd: + res, err = util.GetDump(ctx) + case restoreDumpCmd: + res, err = util.RestoreDump(ctx) + + default: + err = errors.New("Unknown cli command") + } + + var resp Response + if err != nil { + resp.Error = true + resp.Message = fmt.Sprintf("%v", err) + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Println(string(respBytes)) + + return err +} + +func (util *Util) GetHello(ctx context.Context) (*mbctl.GetHelloResult, error) { + var err error + res := &mbctl.GetHelloResult{} + grpcConn, cont, err := client.NewClient(&util.access) + if err != nil { + return res, err + } + defer grpcConn.Close() + + params := &mbctl.GetHelloParams{} + res, err = cont.GetHello(ctx, params) + if err != nil { + return res, err + } + return res, err +} diff --git a/cmd/mbasectl/grant/create.go b/cmd/mbasectl/grant/create.go new file mode 100644 index 0000000..bc3445c --- /dev/null +++ b/cmd/mbasectl/grant/create.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) CreateGrant(cmd *cobra.Command, args []string) { + //util.createGrantParams.Filename = args[0] + res, err := util.createGrant(util.createGrantParams) + printResponse(res, err) +} + +type createGrantParams struct{} +type createGrantResult struct{} + +func (util *Util) createGrant(params createGrantParams) (createGrantResult, error) { + var err error + res := createGrantResult{} + return res, err +} diff --git a/cmd/mbasectl/grant/delete.go b/cmd/mbasectl/grant/delete.go new file mode 100644 index 0000000..f4a5db3 --- /dev/null +++ b/cmd/mbasectl/grant/delete.go @@ -0,0 +1,23 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "github.com/spf13/cobra" +) + +func (util *Util) DeleteGrant(cmd *cobra.Command, args []string) { + //util.deleteGrantParams.Filename = args[0] + res, err := util.deleteGrant(util.deleteGrantParams) + printResponse(res, err) +} + +type deleteGrantParams struct{} +type deleteGrantResult struct{} + +func (util *Util) deleteGrant(params deleteGrantParams) (deleteGrantResult, error) { + var err error + res := deleteGrantResult{} + return res, err +} diff --git a/cmd/mbasectl/grant/printr.go b/cmd/mbasectl/grant/printr.go new file mode 100644 index 0000000..48d8e9e --- /dev/null +++ b/cmd/mbasectl/grant/printr.go @@ -0,0 +1,27 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package account + +import ( + "fmt" + + "sigs.k8s.io/yaml" +) + +func printResponse(res any, err error) { + type Response struct { + Error bool `json:"error" yaml:"error"` + Message string `json:"message,omitempty" yaml:"message,omitempty"` + Result any `json:"result,omitempty" yaml:"result,omitempty"` + } + resp := Response{} + if err != nil { + resp.Error = true + resp.Message = err.Error() + } else { + resp.Result = res + } + respBytes, _ := yaml.Marshal(resp) + fmt.Printf("---\n%s\n", string(respBytes)) +} diff --git a/cmd/mbasectl/grant/util.go b/cmd/mbasectl/grant/util.go new file mode 100644 index 0000000..62cec53 --- /dev/null +++ b/cmd/mbasectl/grant/util.go @@ -0,0 +1,51 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package grant + +import ( + "github.com/spf13/cobra" +) + +type Util struct { + rootCmd *cobra.Command + createGrantParams createGrantParams + deleteGrantParams deleteGrantParams +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) BuildCmds() *cobra.Command { + rootCmd := &cobra.Command{ + Use: "grant", + Short: "\nGrant operations", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + var createGrantCmd = &cobra.Command{ + Use: "create name|id password", + Short: "Create grant", + Args: cobra.ExactArgs(2), + Run: util.CreateGrant, + } + rootCmd.AddCommand(createGrantCmd) + + var deleteGrantCmd = &cobra.Command{ + Use: "delete name|id grant", + Short: "Delete grant", + Args: cobra.ExactArgs(1), + Run: util.DeleteGrant, + } + rootCmd.AddCommand(deleteGrantCmd) + + util.rootCmd = rootCmd + return util.rootCmd +} + diff --git a/cmd/mbasectl/main.go b/cmd/mbasectl/main.go index a6da0e9..eaaf76d 100644 --- a/cmd/mbasectl/main.go +++ b/cmd/mbasectl/main.go @@ -1,398 +1,21 @@ /* - * Copyright 2024 Oleg Borodin + * Copyright 2026 Oleg Borodin */ - package main import ( - "context" - "errors" - "flag" - "fmt" "os" - "os/user" - "path/filepath" - "time" - - "mbase/pkg/client" - "mbase/pkg/mbctl" - - "sigs.k8s.io/yaml" -) - -const ( - defaultHostname = "localhost" - rcFilename = ".certmanager.yaml" - defaultPort uint32 = client.DefaultPort - - getHelloCmd = "getHello" - helpCmd = "help" - - createAccountCmd = "createAccount" - updateAccountCmd = "updateAccount" - deleteAccountCmd = "deleteAccount" - listAccountsCmd = "listAccounts" - - setGrantCmd = "setGrant" - deleteGrantCmd = "deleteGrant" - - getDumpCmd = "getDump" - restoreDumpCmd = "restoreDump" ) func main() { var err error util := NewUtil() - err = util.Exec() + err = util.Build() if err != nil { os.Exit(1) } - os.Exit(0) -} - -type Util struct { - subCmd string - cmdTimeout int64 - access client.Access - cont *mbctl.ControlClient - - caFilenamesList string - certFilename string - keyFilename string - issuerOrganizationName string - issuerOrganizationalUnitName string - issuerCommonName string - issuerID int64 - issuerName string - signerID int64 - signerName string - serviceOrganizationName string - serviceOrganizationalUnitName string - serviceCommonName string - hostnameList string - ipAdressesList string - serviceID int64 - serviceName string - encodingKey string - - accountID int64 - username string - password string - disable bool - newUsername string - newPassword string - operation string - filename string - deleteAllRecords bool -} - -func NewUtil() *Util { - var util Util - util.cmdTimeout = 120 - util.access = client.Access{ - Hostname: defaultHostname, - Port: defaultPort, - Username: "certmanager", - Password: "certmanager", - } - return &util -} - -func (util *Util) GetOpt() error { - var err error - - homeDir := os.Getenv("HOME") - if homeDir == "" { - currUsr, err := user.Current() - if err == nil { - homeDir = currUsr.HomeDir - } - } - if homeDir != "" { - confPath := filepath.Join(homeDir, rcFilename) - confData, err := os.ReadFile(confPath) - if err == nil && len(confData) > 0 { - yaml.Unmarshal(confData, &util.access) - } - } - exeName := filepath.Base(os.Args[0]) - - servicePort := int64(defaultPort) - flag.Int64Var(&util.cmdTimeout, "timeout", util.cmdTimeout, "command execution timeout") - flag.StringVar(&util.access.Hostname, "host", util.access.Hostname, "service hostname") - flag.Int64Var(&servicePort, "port", servicePort, "service port") - flag.StringVar(&util.access.Username, "user", util.access.Username, "access login") - flag.StringVar(&util.access.Password, "pass", util.access.Password, "access password") - - util.access.Port = uint32(servicePort) - - help := func() { - fmt.Println("") - fmt.Printf("Usage: %s [option] command [command option]\n", exeName) - fmt.Printf("\n") - fmt.Printf("Command list: help, %s\n", getHelloCmd) - fmt.Printf(" %s, %s, %s, %s,\n", - createAccountCmd, - deleteAccountCmd, - listAccountsCmd, - updateAccountCmd) - fmt.Printf(" %s, %s\n", - setGrantCmd, - deleteGrantCmd) - fmt.Printf(" %s, %s\n", - getDumpCmd, - restoreDumpCmd) - - fmt.Printf("\n") - fmt.Printf("Global options:\n") - flag.PrintDefaults() - fmt.Printf("\n") - } - flag.Usage = help - flag.Parse() - - args := flag.Args() - - var subCmd string - var subArgs []string - if len(args) > 0 { - subCmd = args[0] - subArgs = args[1:] - } - - switch subCmd { - case helpCmd: - help() - return errors.New("Unknown command") - case getHelloCmd: - flagSet := flag.NewFlagSet(getHelloCmd, flag.ExitOnError) - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - flagSet.Parse(subArgs) - - case createAccountCmd: - flagSet := flag.NewFlagSet(createAccountCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.StringVar(&util.password, "password", util.password, "user password") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case deleteAccountCmd: - flagSet := flag.NewFlagSet(deleteAccountCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case listAccountsCmd: - flagSet := flag.NewFlagSet(listAccountsCmd, flag.ExitOnError) - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case updateAccountCmd: - flagSet := flag.NewFlagSet(updateAccountCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - - flagSet.StringVar(&util.newUsername, "newUsername", util.newUsername, "new user name") - flagSet.StringVar(&util.newPassword, "newPassword", util.newPassword, "new user password") - flagSet.BoolVar(&util.disable, "disable", util.disable, "disable account") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case setGrantCmd: - flagSet := flag.NewFlagSet(setGrantCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case deleteGrantCmd: - flagSet := flag.NewFlagSet(deleteGrantCmd, flag.ExitOnError) - - flagSet.StringVar(&util.username, "username", util.username, "user name") - flagSet.Int64Var(&util.accountID, "accountId", util.accountID, "account ID") - flagSet.StringVar(&util.operation, "operation", util.operation, "grant type") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case getDumpCmd: - flagSet := flag.NewFlagSet(getDumpCmd, flag.ExitOnError) - flagSet.StringVar(&util.filename, "file", util.filename, "dump file name") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - case restoreDumpCmd: - flagSet := flag.NewFlagSet(restoreDumpCmd, flag.ExitOnError) - flagSet.StringVar(&util.filename, "file", util.filename, "dump file name") - - flagSet.Usage = func() { - fmt.Printf("\n") - fmt.Printf("Usage: %s [global options] %s [command options]\n", exeName, subCmd) - fmt.Printf("\n") - fmt.Printf("The command options: none\n") - flagSet.PrintDefaults() - fmt.Printf("\n") - } - flagSet.Parse(subArgs) - util.subCmd = subCmd - - default: - help() - return errors.New("Unknown command") - } - return err -} - -type Response struct { - Error bool `json:"error" yaml:"error"` - Message string `json:"message,omitempty" yaml:"message,omitempty"` - Result any `json:"result,omitempty" yaml:"result,omitempty"` -} - -func (util *Util) Exec() error { - var err error - err = util.GetOpt() + err = util.Exec(os.Args[1:]) if err != nil { - return err + os.Exit(1) } - - var timeout = time.Duration(util.cmdTimeout) * time.Second - ctx, close := context.WithTimeout(context.Background(), timeout) - defer close() - - var res any - switch util.subCmd { - case getHelloCmd: - res, err = util.GetHello(ctx) - - case createAccountCmd: - res, err = util.CreateAccount(ctx) - case updateAccountCmd: - res, err = util.UpdateAccount(ctx) - case listAccountsCmd: - res, err = util.ListAccounts(ctx) - case deleteAccountCmd: - res, err = util.DeleteAccount(ctx) - - case setGrantCmd: - res, err = util.SetGrant(ctx) - case deleteGrantCmd: - res, err = util.DeleteGrant(ctx) - - case getDumpCmd: - res, err = util.GetDump(ctx) - case restoreDumpCmd: - res, err = util.RestoreDump(ctx) - - default: - err = errors.New("Unknown cli command") - } - - var resp Response - if err != nil { - resp.Error = true - resp.Message = fmt.Sprintf("%v", err) - } else { - resp.Result = res - } - respBytes, _ := yaml.Marshal(resp) - fmt.Println(string(respBytes)) - - return err -} - -func (util *Util) GetHello(ctx context.Context) (*mbctl.GetHelloResult, error) { - var err error - res := &mbctl.GetHelloResult{} - grpcConn, cont, err := client.NewClient(&util.access) - if err != nil { - return res, err - } - defer grpcConn.Close() - - params := &mbctl.GetHelloParams{} - res, err = cont.GetHello(ctx, params) - if err != nil { - return res, err - } - return res, err } diff --git a/cmd/mbasectl/util.go b/cmd/mbasectl/util.go new file mode 100644 index 0000000..5d9fed9 --- /dev/null +++ b/cmd/mbasectl/util.go @@ -0,0 +1,49 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package main + +import ( + "os" + "path/filepath" + + "mbase/cmd/mbaseadmin/account" + + "github.com/spf13/cobra" +) + +type Util struct { + rootCmd *cobra.Command +} + +func NewUtil() *Util { + return &Util{} +} + +func (util *Util) GetRooCmd() *cobra.Command { + return util.rootCmd +} + +func (util *Util) Build() error { + var err error + execName := filepath.Base(os.Args[0]) + rootCmd := &cobra.Command{ + Use: execName, + Short: "\nAccount operations", + SilenceUsage: true, + } + rootCmd.CompletionOptions.DisableDefaultCmd = true + + accountUtil := account.NewUtil() + rootCmd.AddCommand(accountUtil.BuildCmds()) + + util.rootCmd = rootCmd + return err +} + +func (util *Util) Exec(args []string) error { + var err error + util.rootCmd.SetArgs(args) + err = util.rootCmd.Execute() + return err +} diff --git a/cmd/mbasedump/dump.go b/cmd/mbasedump/dump.go new file mode 100644 index 0000000..d167e88 --- /dev/null +++ b/cmd/mbasedump/dump.go @@ -0,0 +1,83 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package main + +import ( + "context" + "os" + + "mbase/app/config" + "mbase/app/maindb" + "mbase/pkg/descr" + "mbase/pkg/auxtool" + + "github.com/spf13/cobra" + "go.yaml.in/yaml/v4" +) + +func (util *Util) DumpDatabase(cmd *cobra.Command, args []string) { + util.dumpDatabaseParams.Filename = args[0] + res, err := util.dumpDatabase(util.dumpDatabaseParams) + printResponse(res, err) +} + +type dumpDatabaseParams struct { + Filename string +} +type dumpDatabaseResult struct{} + +func (util *Util) dumpDatabase(params dumpDatabaseParams) (dumpDatabaseResult, error) { + var err error + res := dumpDatabaseResult{} + ctx := context.Background() + + conf := config.NewConfig() + err = conf.ReadFile() + if err != nil { + return res, err + } + err = conf.ReadEnv() + if err != nil { + return res, err + } + db, err := maindb.NewDatabase(conf.DataDir) + if err != nil { + return res, err + } + err = db.OpenDatabase() + if err != nil { + return res, err + } + file := os.Stdout + if params.Filename != "-" { + file, err = os.OpenFile(params.Filename, os.O_CREATE|os.O_WRONLY, 0640) + if err != nil { + return res, err + } + defer file.Close() + } + listAccounts, err := db.CompletedListAccounts(ctx) + if err != nil { + return res, err + } + listGrants, err := db.ListGrants(ctx) + if err != nil { + return res, err + } + dump := descr.Dump{ + Timestamp: auxtool.TimeNow(), + Accounts: listAccounts, + Grants: listGrants, + } + dumpBytes, err := yaml.Marshal(dump) + if err != nil { + return res, err + } + _, err = file.Write(dumpBytes) + if err != nil { + return res, err + } + return res, err +} + diff --git a/cmd/mbasedump/rest.go b/cmd/mbasedump/rest.go new file mode 100644 index 0000000..7a54ece --- /dev/null +++ b/cmd/mbasedump/rest.go @@ -0,0 +1,96 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package main + +import ( + "bytes" + "context" + "io" + "os" + + "mbase/app/config" + "mbase/app/maindb" + "mbase/pkg/descr" + "mbase/pkg/logger" + + "github.com/spf13/cobra" + "go.yaml.in/yaml/v4" +) + +func (util *Util) RestoreDatabase(cmd *cobra.Command, args []string) { + util.restoreDatabaseParams.Filename = args[0] + res, err := util.restoreDatabase(util.restoreDatabaseParams) + printResponse(res, err) +} + +type restoreDatabaseParams struct { + Filename string + DeleteAllRecords bool +} +type restoreDatabaseResult struct{} + +func (util *Util) restoreDatabase(params restoreDatabaseParams) (restoreDatabaseResult, error) { + var err error + res := restoreDatabaseResult{} + ctx := context.Background() + log := logger.NewLogger("restore") + + conf := config.NewConfig() + err = conf.ReadFile() + if err != nil { + return res, err + } + err = conf.ReadEnv() + if err != nil { + return res, err + } + + db, err := maindb.NewDatabase(conf.DataDir) + if err != nil { + return res, err + } + err = db.OpenDatabase() + if err != nil { + return res, err + } + file := os.Stdin + if params.Filename != "-" { + file, err = os.Open(params.Filename) + if err != nil { + return res, err + } + defer file.Close() + } + buffer := bytes.NewBuffer(nil) + _, err = io.Copy(buffer, file) + if err != nil { + return res, err + } + dump := descr.Dump{} + err = yaml.Unmarshal(buffer.Bytes(), &dump) + if err != nil { + return res, err + } + if params.DeleteAllRecords { + err = db.CleanDatabase(ctx) + if err != nil { + return res, err + } + } + for _, account := range dump.Accounts { + log.Infof("Insert account %s", account.Username) + err = db.InsertAccount(ctx, &account) + if err != nil { + log.Errorf("Insert account error: %v", err) + } + } + for _, grant := range dump.Grants { + log.Infof("Insert grant %s for account %d", grant.Operation, grant.AccountID) + err = db.InsertGrant(ctx, &grant) + if err != nil { + log.Errorf("Insert account error: %v", err) + } + } + return res, err +} diff --git a/cmd/mbasedump/util.go b/cmd/mbasedump/util.go index f80707d..d62093c 100644 --- a/cmd/mbasedump/util.go +++ b/cmd/mbasedump/util.go @@ -4,20 +4,10 @@ package main import ( - "bytes" - "context" - "io" "os" "path/filepath" - "mbase/app/config" - "mbase/app/maindb" - "mbase/app/descr" - "mbase/pkg/auxtool" - "mbase/pkg/logger" - "github.com/spf13/cobra" - "go.yaml.in/yaml/v4" ) type Util struct { @@ -72,144 +62,3 @@ func (util *Util) Exec(args []string) error { return err } -func (util *Util) DumpDatabase(cmd *cobra.Command, args []string) { - util.dumpDatabaseParams.Filename = args[0] - res, err := util.dumpDatabase(util.dumpDatabaseParams) - printResponse(res, err) -} - -type dumpDatabaseParams struct { - Filename string -} -type dumpDatabaseResult struct{} - -func (util *Util) dumpDatabase(params dumpDatabaseParams) (dumpDatabaseResult, error) { - var err error - res := dumpDatabaseResult{} - ctx := context.Background() - - conf := config.NewConfig() - err = conf.ReadFile() - if err != nil { - return res, err - } - err = conf.ReadEnv() - if err != nil { - return res, err - } - db, err := maindb.NewDatabase(conf.DataDir) - if err != nil { - return res, err - } - err = db.OpenDatabase() - if err != nil { - return res, err - } - file := os.Stdout - if params.Filename != "-" { - file, err = os.OpenFile(params.Filename, os.O_CREATE|os.O_WRONLY, 0640) - if err != nil { - return res, err - } - defer file.Close() - } - listAccounts, err := db.CompletedListAccounts(ctx) - if err != nil { - return res, err - } - listGrants, err := db.ListGrants(ctx) - if err != nil { - return res, err - } - dump := descr.Dump{ - Timestamp: auxtool.TimeNow(), - Accounts: listAccounts, - Grants: listGrants, - } - dumpBytes, err := yaml.Marshal(dump) - if err != nil { - return res, err - } - _, err = file.Write(dumpBytes) - if err != nil { - return res, err - } - return res, err -} - -func (util *Util) RestoreDatabase(cmd *cobra.Command, args []string) { - util.restoreDatabaseParams.Filename = args[0] - res, err := util.restoreDatabase(util.restoreDatabaseParams) - printResponse(res, err) -} - -type restoreDatabaseParams struct { - Filename string - DeleteAllRecords bool -} -type restoreDatabaseResult struct{} - -func (util *Util) restoreDatabase(params restoreDatabaseParams) (restoreDatabaseResult, error) { - var err error - res := restoreDatabaseResult{} - ctx := context.Background() - log := logger.NewLogger("restore") - - conf := config.NewConfig() - err = conf.ReadFile() - if err != nil { - return res, err - } - err = conf.ReadEnv() - if err != nil { - return res, err - } - - db, err := maindb.NewDatabase(conf.DataDir) - if err != nil { - return res, err - } - err = db.OpenDatabase() - if err != nil { - return res, err - } - file := os.Stdin - if params.Filename != "-" { - file, err = os.Open(params.Filename) - if err != nil { - return res, err - } - defer file.Close() - } - buffer := bytes.NewBuffer(nil) - _, err = io.Copy(buffer, file) - if err != nil { - return res, err - } - dump := descr.Dump{} - err = yaml.Unmarshal(buffer.Bytes(), &dump) - if err != nil { - return res, err - } - if params.DeleteAllRecords { - err = db.CleanDatabase(ctx) - if err != nil { - return res, err - } - } - for _, account := range dump.Accounts { - log.Infof("Insert account %s", account.Username) - err = db.InsertAccount(ctx, &account) - if err != nil { - log.Errorf("Insert account error: %v", err) - } - } - for _, grant := range dump.Grants { - log.Infof("Insert grant %s for account %d", grant.Operation, grant.AccountID) - err = db.InsertGrant(ctx, &grant) - if err != nil { - log.Errorf("Insert account error: %v", err) - } - } - return res, err -} diff --git a/go.mod b/go.mod index d6036be..b6ef91f 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,9 @@ go 1.26.2 require ( github.com/gin-gonic/gin v1.12.0 + github.com/google/uuid v1.6.0 github.com/jmoiron/sqlx v1.4.0 github.com/mattn/go-sqlite3 v1.14.44 - github.com/sirupsen/logrus v1.9.4 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 go.yaml.in/yaml/v4 v4.0.0-rc.4 diff --git a/go.sum b/go.sum index 1fa7fa3..bdb21b0 100644 --- a/go.sum +++ b/go.sum @@ -82,8 +82,6 @@ github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRC github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= -github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= diff --git a/pkg/auxgin/corsmw.go b/pkg/auxgin/corsmw.go deleted file mode 100644 index 6bfd3d3..0000000 --- a/pkg/auxgin/corsmw.go +++ /dev/null @@ -1,31 +0,0 @@ -package auxgin - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" -) - -func CorsMiddleware() gin.HandlerFunc { - - headers := []string{"Content-Type", "Content-Length", "Accept-Encoding", "X-CSRF-Token", "Authorization"} - headerList := strings.Join(headers, ",") - - methods := []string{"POST", "GET", "OPTIONS", "PUT", "DELETE", "UPDATE"} - methodList := strings.Join(methods, ",") - - return func(gctx *gin.Context) { - gctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") - gctx.Writer.Header().Set("Access-Control-Max-Age", "86400") - gctx.Writer.Header().Set("Access-Control-Allow-Methods", methodList) - gctx.Writer.Header().Set("Access-Control-Allow-Headers", headerList) - gctx.Writer.Header().Set("Access-Control-Allow-Credentials", "true") - - if gctx.Request.Method == "OPTIONS" { - gctx.AbortWithStatus(http.StatusOK) - } else { - gctx.Next() - } - } -} diff --git a/pkg/auxgin/logmw.go b/pkg/auxgin/logmw.go deleted file mode 100644 index af221fd..0000000 --- a/pkg/auxgin/logmw.go +++ /dev/null @@ -1,60 +0,0 @@ -package auxgin - -import ( - "bytes" - "fmt" - "time" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -func LogMiddleware() gin.HandlerFunc { - return func(ctx *gin.Context) { - - start := time.Now() - - ctx.Next() - - var reqSize int64 - var method string - var reqURI string - var remAddr string - if ctx.Request != nil { - reqSize = ctx.Request.ContentLength - method = ctx.Request.Method - reqURI = ctx.Request.RequestURI - remAddr = ctx.RemoteIP() - } - - duration := time.Since(start).Microseconds() - - var resCode int - var resSize int - if ctx.Writer != nil { - resCode = ctx.Writer.Status() - resSize = ctx.Writer.Size() - } - - logString := fmt.Sprintf("%s %s %s in=%d out=%d res=%d %dms", - remAddr, method, reqURI, reqSize, resSize, resCode, duration) - - logger := logrus.WithField("object", "accesslog") - logger.Infoln(logString) - } -} - -type LogWriter struct { - gin.ResponseWriter - body *bytes.Buffer -} - -func (lw LogWriter) Write(data []byte) (int, error) { - lw.body.Write(data) - return lw.ResponseWriter.Write(data) -} - -func (lw LogWriter) WriteString(data string) (int, error) { - lw.body.WriteString(data) - return lw.ResponseWriter.WriteString(data) -} diff --git a/pkg/auxgin/reqlog.go b/pkg/auxgin/reqlog.go deleted file mode 100644 index 368b42f..0000000 --- a/pkg/auxgin/reqlog.go +++ /dev/null @@ -1,34 +0,0 @@ -package auxgin - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "strings" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -func RequestLogMiddleware() gin.HandlerFunc { - return func(context *gin.Context) { - - contentType := context.GetHeader("Content-Type") - contentType = strings.ToLower(contentType) - - var requestBody []byte - if context.Request.Body != nil { - requestBody, _ = ioutil.ReadAll(context.Request.Body) - } - - if strings.Contains(contentType, "application/json") && context.Request.Method == "POST" { - buffer := bytes.NewBuffer(nil) - json.Indent(buffer, requestBody, "", " ") - logger := logrus.WithField("object", "requestlog") - logger.Infoln("request:\n", buffer.String()) - } - - context.Request.Body = ioutil.NopCloser(bytes.NewReader(requestBody)) - context.Next() - } -} diff --git a/pkg/auxgin/reslog.go b/pkg/auxgin/reslog.go deleted file mode 100644 index 7afc543..0000000 --- a/pkg/auxgin/reslog.go +++ /dev/null @@ -1,32 +0,0 @@ -package auxgin - -import ( - "bytes" - "encoding/json" - "strings" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" -) - -func ResponseLogMiddleware() gin.HandlerFunc { - return func(context *gin.Context) { - contentType := context.GetHeader("Content-Type") - contentType = strings.ToLower(contentType) - - writer := &LogWriter{ - body: bytes.NewBuffer(nil), - ResponseWriter: context.Writer, - } - context.Writer = writer - - context.Next() - - if strings.Contains(contentType, "application/json") { - buffer := bytes.NewBuffer(nil) - json.Indent(buffer, writer.body.Bytes(), "", " ") - logger := logrus.WithField("object", "responselog") - logger.Infoln("request:\n", buffer.String()) - } - } -} diff --git a/pkg/auxuuid/uuid.go b/pkg/auxuuid/uuid.go new file mode 100644 index 0000000..b84c925 --- /dev/null +++ b/pkg/auxuuid/uuid.go @@ -0,0 +1,14 @@ +/* + * Copyright 2026 Oleg Borodin + */ +package auxuuid + +import ( + "github.com/google/uuid" +) + +const ZeroUUID string = "00000000-0000-0000-0000-000000000000" + +func NewUUID() string { + return uuid.New().String() +} diff --git a/pkg/common/common.go b/pkg/common/common.go deleted file mode 100644 index 805d0c7..0000000 --- a/pkg/common/common.go +++ /dev/null @@ -1 +0,0 @@ -package common diff --git a/app/descr/descriptor.go b/pkg/descr/descr.go similarity index 84% rename from app/descr/descriptor.go rename to pkg/descr/descr.go index 93dbf43..bb525c6 100644 --- a/app/descr/descriptor.go +++ b/pkg/descr/descr.go @@ -12,7 +12,7 @@ type Dump struct { } type Account struct { - ID int64 `json:"id" yaml:"id" db:"id"` + ID string `json:"id" yaml:"id" db:"id"` Username string `json:"username" yaml:"username" db:"username"` Passhash string `json:"passhash" yaml:"passhash" db:"passhash"` Disabled bool `json:"disabled" yaml:"disabled" db:"disabled"` @@ -21,8 +21,8 @@ type Account struct { } type Grant struct { - ID int64 `json:"id" yaml:"id" db:"id"` - AccountID int64 `json:"accountID" yaml:"accountID" db:"account_id"` + ID string `json:"id" yaml:"id" db:"id"` + AccountID string `json:"accountID" yaml:"accountID" db:"account_id"` Operation string `json:"operation" yaml:"operation" db:"operation"` CreatedAt string `json:"createdAt" yaml:"createdAt" db:"created_at"` } diff --git a/pkg/mbctl/mbctl.pb.go b/pkg/mbctl/mbctl.pb.go index 177077c..36291a7 100644 --- a/pkg/mbctl/mbctl.pb.go +++ b/pkg/mbctl/mbctl.pb.go @@ -192,7 +192,7 @@ func (*RestoreDumpResult) Descriptor() ([]byte, []int) { type SetGrantParams struct { state protoimpl.MessageState `protogen:"open.v1"` Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"` + AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"` Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -235,11 +235,11 @@ func (x *SetGrantParams) GetUsername() string { return "" } -func (x *SetGrantParams) GetAccountID() int64 { +func (x *SetGrantParams) GetAccountID() string { if x != nil { return x.AccountID } - return 0 + return "" } func (x *SetGrantParams) GetOperation() string { @@ -251,7 +251,7 @@ func (x *SetGrantParams) GetOperation() string { type SetGrantResult struct { state protoimpl.MessageState `protogen:"open.v1"` - GrantID int64 `protobuf:"varint,1,opt,name=grantID,proto3" json:"grantID,omitempty"` + GrantID string `protobuf:"bytes,1,opt,name=grantID,proto3" json:"grantID,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -286,17 +286,17 @@ func (*SetGrantResult) Descriptor() ([]byte, []int) { return file_mbctl_proto_rawDescGZIP(), []int{5} } -func (x *SetGrantResult) GetGrantID() int64 { +func (x *SetGrantResult) GetGrantID() string { if x != nil { return x.GrantID } - return 0 + return "" } type DeleteGrantParams struct { state protoimpl.MessageState `protogen:"open.v1"` Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"` + AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"` Operation string `protobuf:"bytes,3,opt,name=operation,proto3" json:"operation,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -339,11 +339,11 @@ func (x *DeleteGrantParams) GetUsername() string { return "" } -func (x *DeleteGrantParams) GetAccountID() int64 { +func (x *DeleteGrantParams) GetAccountID() string { if x != nil { return x.AccountID } - return 0 + return "" } func (x *DeleteGrantParams) GetOperation() string { @@ -443,7 +443,7 @@ func (x *CreateAccountParams) GetPassword() string { type CreateAccountResult struct { state protoimpl.MessageState `protogen:"open.v1"` - AccountID int64 `protobuf:"varint,1,opt,name=accountID,proto3" json:"accountID,omitempty"` + AccountID string `protobuf:"bytes,1,opt,name=accountID,proto3" json:"accountID,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -478,17 +478,17 @@ func (*CreateAccountResult) Descriptor() ([]byte, []int) { return file_mbctl_proto_rawDescGZIP(), []int{9} } -func (x *CreateAccountResult) GetAccountID() int64 { +func (x *CreateAccountResult) GetAccountID() string { if x != nil { return x.AccountID } - return 0 + return "" } type DeleteAccountParams struct { state protoimpl.MessageState `protogen:"open.v1"` Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"` + AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -530,11 +530,11 @@ func (x *DeleteAccountParams) GetUsername() string { return "" } -func (x *DeleteAccountParams) GetAccountID() int64 { +func (x *DeleteAccountParams) GetAccountID() string { if x != nil { return x.AccountID } - return 0 + return "" } type DeleteAccountResult struct { @@ -576,7 +576,7 @@ func (*DeleteAccountResult) Descriptor() ([]byte, []int) { type UpdateAccountParams struct { state protoimpl.MessageState `protogen:"open.v1"` Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"` - AccountID int64 `protobuf:"varint,2,opt,name=accountID,proto3" json:"accountID,omitempty"` + AccountID string `protobuf:"bytes,2,opt,name=accountID,proto3" json:"accountID,omitempty"` NewUsername string `protobuf:"bytes,3,opt,name=newUsername,proto3" json:"newUsername,omitempty"` NewPassword string `protobuf:"bytes,4,opt,name=newPassword,proto3" json:"newPassword,omitempty"` Disabled bool `protobuf:"varint,5,opt,name=disabled,proto3" json:"disabled,omitempty"` @@ -621,11 +621,11 @@ func (x *UpdateAccountParams) GetUsername() string { return "" } -func (x *UpdateAccountParams) GetAccountID() int64 { +func (x *UpdateAccountParams) GetAccountID() string { if x != nil { return x.AccountID } - return 0 + return "" } func (x *UpdateAccountParams) GetNewUsername() string { @@ -1063,17 +1063,17 @@ var file_mbctl_proto_rawDesc = string([]byte{ 0x65, 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2a, 0x0a, 0x0e, 0x73, 0x65, 0x74, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, + 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x6b, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x13, 0x0a, 0x11, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x65, 0x73, @@ -1084,19 +1084,19 @@ var file_mbctl_proto_rawDesc = string([]byte{ 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x33, 0x0a, 0x13, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x4f, 0x0a, 0x13, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x22, 0x15, 0x0a, 0x13, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xaf, 0x01, 0x0a, 0x13, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6e, 0x65, 0x77, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, diff --git a/proto/mbctl.proto b/proto/mbctl.proto index c285ada..c52a1c6 100644 --- a/proto/mbctl.proto +++ b/proto/mbctl.proto @@ -35,16 +35,16 @@ message restoreDumpResult { message setGrantParams { string username = 1; - int64 accountID = 2; + string accountID = 2; string operation = 3; } message setGrantResult { - int64 grantID = 1; + string grantID = 1; } message deleteGrantParams { string username = 1; - int64 accountID = 2; + string accountID = 2; string operation = 3; } message deleteGrantResult {} @@ -55,18 +55,18 @@ message createAccountParams { string password = 2; } message createAccountResult { - int64 accountID = 1; + string accountID = 1; } message deleteAccountParams { string username = 1; - int64 accountID = 2; + string accountID = 2; } message deleteAccountResult {} message updateAccountParams { string username = 1; - int64 accountID = 2; + string accountID = 2; string newUsername = 3; string newPassword = 4; bool disabled = 5;