package models import ( "context" "time" "code.crute.us/mcrute/golib/db/mongodb/v2" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" ) const accountCol = "accounts" type AccountStore interface { List(context.Context) ([]*Account, error) ListForUser(context.Context, *User) ([]*Account, error) Get(context.Context, string) (*Account, error) // Error on not found GetForUser(context.Context, string, *User) (*Account, error) // Error on not found Put(context.Context, *Account) error Delete(context.Context, *Account) error } type Account struct { ShortName string `bson:"_id" json:"short_name"` AccountType string `json:"account_type"` AccountNumber int `json:"account_number"` Name string `json:"name"` ConsoleSessionDuration time.Duration `json:"console_session_duration,omitempty"` AdminVaultMaterial string `json:"admin_vault_material,omitempty"` AssumedRoleARN string `json:"assumed_role_arn"` DefaultRegion string `json:"default_region"` Users []string `json:"users,omitempty"` Deleted *time.Time `json:"deleted,omitempty" bson:"deleted,omitempty"` } func (a *Account) ConsoleSessionDurationSecs() int64 { return int64(a.ConsoleSessionDuration.Seconds()) } func (a *Account) CanBeModifiedBy(u *User) bool { return u.IsAdmin } type MongoDbAccountStore struct { Db *mongodb.Mongo // ReturnDeleted will allow all methods to return deleted items. items // where the Deleted field is set will not be returned. Non-admin // use-cases should leave this set to false. ReturnDeleted bool } // List returns all accounts in the system. func (s *MongoDbAccountStore) List(ctx context.Context) ([]*Account, error) { var out []*Account filter := bson.M{} if !s.ReturnDeleted { filter["deleted"] = primitive.Null{} } if err := s.Db.FindAllByFilter(ctx, accountCol, filter, &out); err != nil { return nil, err } return out, nil } // ListForUser returns all accounts for which the user has access. This is the // authorized version of List. // // Note this does not handle the case where a user is an admin but not // explicitly listed in the allowed users list for an account. For that case // just use List directly. func (s *MongoDbAccountStore) ListForUser(ctx context.Context, u *User) ([]*Account, error) { var out []*Account filter := mongodb.AnyInTopLevelArray("users", u.Username) if !s.ReturnDeleted { filter["deleted"] = primitive.Null{} } if err := s.Db.FindAllByFilter(ctx, accountCol, filter, &out); err != nil { return nil, err } return out, nil } func (s *MongoDbAccountStore) Get(ctx context.Context, id string) (*Account, error) { var a Account filter := bson.M{"_id": id} if !s.ReturnDeleted { filter["deleted"] = primitive.Null{} } if err := s.Db.FindOneByFilter(ctx, accountCol, filter, &a); err != nil { return nil, err } return &a, nil } // GetForUser returns an account if the user has access to this account, // otherwise it returns an error. This is the authorized version of Get. func (s *MongoDbAccountStore) GetForUser(ctx context.Context, id string, u *User) (*Account, error) { var a Account var filter bson.M if u.IsAdmin { filter = bson.M{"_id": id} } else { filter = mongodb.AnyInTopLevelArray("users", u.Username) filter["_id"] = id } if !s.ReturnDeleted { filter["deleted"] = primitive.Null{} } if err := s.Db.FindOneByFilter(ctx, accountCol, filter, &a); err != nil { return nil, err } return &a, nil } func (s *MongoDbAccountStore) Put(ctx context.Context, a *Account) error { if err := s.Db.ReplaceOneById(ctx, accountCol, a.ShortName, a); err != nil { return err } return nil } func (s *MongoDbAccountStore) Delete(ctx context.Context, a *Account) error { a, err := s.Get(ctx, a.ShortName) if err != nil { return err } now := time.Now() a.Deleted = &now return s.Put(ctx, a) } var _ AccountStore = (*MongoDbAccountStore)(nil)