diff options
Diffstat (limited to 'app/models/user.go')
-rw-r--r-- | app/models/user.go | 56 |
1 files changed, 44 insertions, 12 deletions
diff --git a/app/models/user.go b/app/models/user.go index 0cbd92d..2871380 100644 --- a/app/models/user.go +++ b/app/models/user.go | |||
@@ -2,8 +2,11 @@ package models | |||
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "context" | 4 | "context" |
5 | "time" | ||
5 | 6 | ||
6 | "code.crute.us/mcrute/golib/db/mongodb" | 7 | "code.crute.us/mcrute/golib/db/mongodb" |
8 | "go.mongodb.org/mongo-driver/bson" | ||
9 | "go.mongodb.org/mongo-driver/bson/primitive" | ||
7 | ) | 10 | ) |
8 | 11 | ||
9 | const userCol = "users" | 12 | const userCol = "users" |
@@ -16,17 +19,21 @@ type UserStore interface { | |||
16 | } | 19 | } |
17 | 20 | ||
18 | type AuthToken struct { | 21 | type AuthToken struct { |
19 | Kind string | 22 | Kind string `json:"kind"` |
20 | Token string | 23 | Token string `json:"token"` |
21 | RefreshToken string | 24 | |
25 | // Do not expose refresh tokens in JSON as they are long-lived tokens that | ||
26 | // are harder to invalidate and thus rather security sensitive. | ||
27 | RefreshToken string `json:"-"` | ||
22 | } | 28 | } |
23 | 29 | ||
24 | type User struct { | 30 | type User struct { |
25 | Username string `bson:"_id"` | 31 | Username string `bson:"_id" json:"key_id"` |
26 | IsAdmin bool | 32 | IsAdmin bool `json:"is_admin"` |
27 | IsService bool | 33 | IsService bool `json:"is_service"` |
28 | Keys map[string]*SessionKey // kid -> key | 34 | Keys map[string]*SessionKey `json:"keys,omitempty"` // kid -> key |
29 | AuthTokens map[string]*AuthToken // kind -> token | 35 | AuthTokens map[string]*AuthToken `json:"auth_tokens,omitempty"` // kind -> token |
36 | Deleted *time.Time `json:"deleted,omitempty"` | ||
30 | } | 37 | } |
31 | 38 | ||
32 | // GCKeys garbage collects keys that are no longer valid | 39 | // GCKeys garbage collects keys that are no longer valid |
@@ -64,21 +71,41 @@ func (u *User) AddToken(t *AuthToken) { | |||
64 | 71 | ||
65 | type MongoDbUserStore struct { | 72 | type MongoDbUserStore struct { |
66 | Db *mongodb.Mongo | 73 | Db *mongodb.Mongo |
74 | |||
75 | // ReturnDeleted will allow all methods to return deleted items. By default | ||
76 | // items where the Deleted field is set will not be returned. This should | ||
77 | // be the common cast for most code using this store but in some Admin | ||
78 | // use-cases it would be useful to show deleted accounts. | ||
79 | ReturnDeleted bool | ||
67 | } | 80 | } |
68 | 81 | ||
69 | func (s *MongoDbUserStore) List(ctx context.Context) ([]*User, error) { | 82 | func (s *MongoDbUserStore) List(ctx context.Context) ([]*User, error) { |
70 | var out []*User | 83 | var out []*User |
71 | if err := s.Db.FindAll(ctx, userCol, &out); err != nil { | 84 | |
85 | filter := bson.M{} | ||
86 | if !s.ReturnDeleted { | ||
87 | filter["deleted"] = primitive.Null{} | ||
88 | } | ||
89 | |||
90 | if err := s.Db.FindAllByFilter(ctx, userCol, filter, &out); err != nil { | ||
72 | return nil, err | 91 | return nil, err |
73 | } | 92 | } |
93 | |||
74 | return out, nil | 94 | return out, nil |
75 | } | 95 | } |
76 | 96 | ||
77 | func (s *MongoDbUserStore) Get(ctx context.Context, username string) (*User, error) { | 97 | func (s *MongoDbUserStore) Get(ctx context.Context, username string) (*User, error) { |
78 | var u User | 98 | var u User |
79 | if err := s.Db.FindOneById(ctx, userCol, username, &u); err != nil { | 99 | |
100 | filter := bson.M{"_id": username} | ||
101 | if !s.ReturnDeleted { | ||
102 | filter["deleted"] = primitive.Null{} | ||
103 | } | ||
104 | |||
105 | if err := s.Db.FindOneByFilter(ctx, userCol, filter, &u); err != nil { | ||
80 | return nil, err | 106 | return nil, err |
81 | } | 107 | } |
108 | |||
82 | return &u, nil | 109 | return &u, nil |
83 | } | 110 | } |
84 | 111 | ||
@@ -90,10 +117,15 @@ func (s *MongoDbUserStore) Put(ctx context.Context, u *User) error { | |||
90 | } | 117 | } |
91 | 118 | ||
92 | func (s *MongoDbUserStore) Delete(ctx context.Context, u *User) error { | 119 | func (s *MongoDbUserStore) Delete(ctx context.Context, u *User) error { |
93 | if err := s.Db.DeleteOneById(ctx, userCol, u.Username); err != nil { | 120 | u, err := s.Get(ctx, u.Username) |
121 | if err != nil { | ||
94 | return err | 122 | return err |
95 | } | 123 | } |
96 | return nil | 124 | |
125 | now := time.Now() | ||
126 | u.Deleted = &now | ||
127 | |||
128 | return s.Put(ctx, u) | ||
97 | } | 129 | } |
98 | 130 | ||
99 | var _ UserStore = (*MongoDbUserStore)(nil) | 131 | var _ UserStore = (*MongoDbUserStore)(nil) |