aboutsummaryrefslogtreecommitdiff
path: root/app/models/account.go
blob: 0ae1821a694955eb96228ecaa3ecbe210c9bbba0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package models

import (
	"context"
	"fmt"
	"time"

	"code.crute.us/mcrute/golib/db/mongodb"
)

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"`
	AccountType            string
	AccountNumber          int
	Name                   string
	ConsoleSessionDuration time.Duration
	VaultMaterial          string
	DefaultRegion          string
	Users                  []string
}

func (a *Account) ConsoleSessionDurationSecs() int64 {
	return int64(a.ConsoleSessionDuration.Seconds())
}

func (a *Account) CanAccess(u *User) bool {
	if u.IsAdmin {
		return true
	}
	// Linear search should be fine for now, these lists are pretty small
	for _, n := range a.Users {
		if n == u.Username {
			return true
		}
	}
	return false
}

type MongoDbAccountStore struct {
	Db *mongodb.Mongo
}

// List returns all accounts in the system.
func (s *MongoDbAccountStore) List(ctx context.Context) ([]*Account, error) {
	var out []*Account
	if err := s.Db.FindAll(ctx, accountCol, &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 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
	if err := s.Db.FindOneById(ctx, accountCol, id, &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) {
	a, err := s.Get(ctx, id)
	if err != nil {
		return nil, err
	}

	if !a.CanAccess(u) {
		return nil, fmt.Errorf("User does not have access to account")
	}

	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 {
	if err := s.Db.DeleteOneById(ctx, accountCol, a.ShortName); err != nil {
		return err
	}
	return nil
}

var _ AccountStore = (*MongoDbAccountStore)(nil)