From d9a8d201e6314a7f18efb3c6f5529e3c82e5aa70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20D=C3=B6ll?= Date: Fri, 26 Apr 2024 19:42:31 +0000 Subject: [PATCH] wip: create account --- cmd/api/cmd/root.go | 3 +- internal/api/controllers/accounts.go | 91 ++++++++++++++++++++++++++++ internal/api/services/api.go | 25 +++++++- 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 internal/api/controllers/accounts.go diff --git a/cmd/api/cmd/root.go b/cmd/api/cmd/root.go index 1cc1fdd9..2d35de38 100644 --- a/cmd/api/cmd/root.go +++ b/cmd/api/cmd/root.go @@ -91,8 +91,9 @@ func (s *WebSrv) Start(ctx context.Context, ready server.ReadyFunc, run server.R sc := controllers.NewSystemsController(db) vc := controllers.NewVersionController(build) oc := controllers.NewOperatorsController(db) + ac := controllers.NewAccountsController(db) - handlers := services.NewApiHandlers(sc, tc, vc, oc) + handlers := services.NewApiHandlers(sc, tc, vc, oc, ac) handler := openapi.NewStrictHandler(handlers, nil) openapi.RegisterHandlers(app, handler) diff --git a/internal/api/controllers/accounts.go b/internal/api/controllers/accounts.go new file mode 100644 index 00000000..2fbdd081 --- /dev/null +++ b/internal/api/controllers/accounts.go @@ -0,0 +1,91 @@ +package controllers + +import ( + "context" + + "github.com/google/uuid" + "github.com/nats-io/jwt" + "github.com/nats-io/nkeys" + "github.com/zeiss/typhoon/internal/api/models" + "github.com/zeiss/typhoon/internal/api/ports" +) + +// AccountsController ... +type AccountsController struct { + db ports.Accounts +} + +// NewAccountsController ... +func NewAccountsController(db ports.Accounts) *AccountsController { + return &AccountsController{db} +} + +// CreateAccount ... +func (c *AccountsController) CreateAccount(ctx context.Context, name string, operatorID uuid.UUID) (*models.Account, error) { + pk, err := nkeys.CreateAccount() + if err != nil { + return nil, err + } + + id, err := pk.PublicKey() + if err != nil { + return nil, err + } + + seed, err := pk.Seed() + if err != nil { + return nil, err + } + + // Create a signing key for the account + sk, err := nkeys.CreateAccount() + if err != nil { + return nil, err + } + + spk, err := sk.PublicKey() + if err != nil { + return nil, err + } + + skSeed, err := sk.Seed() + if err != nil { + return nil, err + } + + // Create a token for the account + oc := jwt.NewAccountClaims(id) + oc.Name = name + oc.SigningKeys.Add(spk) + + token, err := oc.Encode(pk) + if err != nil { + return nil, err + } + + ac := &models.Account{ + Name: name, + OperatorID: operatorID, + Key: models.NKey{ + ID: id, + Seed: seed, + }, + SigningKeys: []models.NKey{ + { + ID: spk, + Seed: skSeed, + }, + }, + Token: models.Token{ + ID: id, + Token: token, + }, + } + + err = c.db.CreateAccount(ctx, ac) + if err != nil { + return nil, err + } + + return ac, nil +} diff --git a/internal/api/services/api.go b/internal/api/services/api.go index 58c604dd..e5668e87 100644 --- a/internal/api/services/api.go +++ b/internal/api/services/api.go @@ -15,13 +15,14 @@ type ApiHandlers struct { teams *controllers.TeamsController version *controllers.VersionController operators *controllers.OperatorsController + accounts *controllers.AccountsController openapi.Unimplemented } // NewApiHandlers ... -func NewApiHandlers(systems *controllers.SystemsController, teams *controllers.TeamsController, version *controllers.VersionController, operators *controllers.OperatorsController) *ApiHandlers { - return &ApiHandlers{systems: systems, teams: teams, version: version, operators: operators} +func NewApiHandlers(systems *controllers.SystemsController, teams *controllers.TeamsController, version *controllers.VersionController, operators *controllers.OperatorsController, accounts *controllers.AccountsController) *ApiHandlers { + return &ApiHandlers{systems: systems, teams: teams, version: version, operators: operators, accounts: accounts} } // CreateOperator ... @@ -34,6 +35,26 @@ func (a *ApiHandlers) CreateOperator(ctx context.Context, req openapi.CreateOper return openapi.CreateOperator201JSONResponse(openapi.Operator{Id: &operator.ID, Name: operator.Name}), nil } +// CreateOperatorAccount ... +func (a *ApiHandlers) CreateOperatorAccount(ctx context.Context, req openapi.CreateOperatorAccountRequestObject) (openapi.CreateOperatorAccountResponseObject, error) { + account, err := a.accounts.CreateAccount(ctx, req.Body.Name, req.OperatorId) + if err != nil { + return nil, err + } + + resp := openapi.CreateOperatorAccount201JSONResponse( + openapi.Account{ + Id: &account.ID, + Name: account.Name, + CreatedAt: &account.CreatedAt, + UpdatedAt: &account.UpdatedAt, + DeletedAt: &account.DeletedAt.Time, + }, + ) + + return openapi.CreateOperatorAccount201JSONResponse(resp), nil +} + // // GetOperator ... // func (a *ApiHandlers) GetOperator(ctx context.Context, req openapi.GetOperatorRequestObject) (openapi.GetOperatorResponseObject, error) { // operator, err := a.operators.GetOperator(ctx, req.OperatorId)