-
Notifications
You must be signed in to change notification settings - Fork 1
/
sessionUser.go
150 lines (126 loc) · 4.51 KB
/
sessionUser.go
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package wsHelpers
import (
"context"
"errors"
"github.com/olahol/melody"
"github.com/pixlise/core/v4/api/dbCollections"
"github.com/pixlise/core/v4/core/jwtparser"
"github.com/pixlise/core/v4/core/utils"
protos "github.com/pixlise/core/v4/generated-protos"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type SessionUser struct {
SessionId string
User *protos.UserInfo
Permissions map[string]bool
MemberOfGroupIds []string
NotificationSubscribed bool
}
func GetSessionUser(s *melody.Session) (SessionUser, error) {
var connectingUser SessionUser
if _connectingUser, ok := s.Get("user"); !ok {
return connectingUser, errors.New("User not found on session")
} else {
connectingUser, ok = _connectingUser.(SessionUser)
if !ok {
return connectingUser, errors.New("User details corrupt on session")
}
}
return connectingUser, nil
}
var cachedUserGroupMembership = map[string][]string{}
// JWT user has the user ID and permissions that we get from Auth0. The rest is handled
// within PIXLISE, so lets read our DB to see if this user exists and get their
// user name, email, icon, etc
func MakeSessionUser(sessionId string, jwtUser jwtparser.JWTUserInfo, db *mongo.Database) (*SessionUser, error) {
// Ensure we have the full user ID, as our system was previously cutting the prefix
// off of Auth0 user ids
userId := utils.FixUserId(jwtUser.UserID)
userDBItem, err := GetDBUser(userId, db)
if err != nil {
return nil, err
}
return makeSessionUser(userId, sessionId, jwtUser.Permissions, userDBItem, db)
}
// If we have a successful login and the user is not in our DB, we write a default record
// for them, so if they change their details we have a spot to save it already
// NOTE: This is (at time of writing) the only way to add a user to the DB
func CreateDBUser(sessionId string, jwtUser jwtparser.JWTUserInfo, db *mongo.Database) (*SessionUser, error) {
userId := utils.FixUserId(jwtUser.UserID)
userDBItem := &protos.UserDBItem{
Id: userId,
Info: &protos.UserInfo{
Id: userId,
Name: jwtUser.Name,
Email: jwtUser.Email,
// IconURL
},
DataCollectionVersion: "",
//NotificationSettings
}
_, err := db.Collection(dbCollections.UsersName).InsertOne(context.TODO(), userDBItem)
if err != nil {
return nil, err
}
// TODO: do we insert it in any groups?
return makeSessionUser(userId, sessionId, jwtUser.Permissions, userDBItem, db)
}
func makeSessionUser(userId string, sessionId string, permissions map[string]bool, userDBItem *protos.UserDBItem, db *mongo.Database) (*SessionUser, error) {
ourGroups := map[string]bool{}
// Now we read all the groups and find which ones we are members of
filter := bson.D{}
opts := options.Find()
cursor, err := db.Collection(dbCollections.UserGroupsName).Find(context.TODO(), filter, opts)
if err != nil {
return nil, err
}
userGroups := []*protos.UserGroupDB{}
err = cursor.All(context.TODO(), &userGroups)
if err != nil {
return nil, err
}
for _, userGroup := range userGroups {
if userGroup.Members != nil {
if utils.ItemInSlice(userId, userGroup.Members.UserIds) {
ourGroups[userGroup.Id] = true
}
} else if userGroup.Viewers != nil {
if utils.ItemInSlice(userId, userGroup.Viewers.UserIds) {
ourGroups[userGroup.Id] = true
}
}
}
// Finally, if we are in a group which itself is also within a group, find again
// TODO: This may not detect outside of 2 levels deep grouping, we may want more...
for _, userGroup := range userGroups {
for groupToCheck, _ := range ourGroups {
if userGroup.Id != groupToCheck {
if userGroup.Members != nil {
if utils.ItemInSlice(groupToCheck, userGroup.Members.GroupIds) {
ourGroups[userGroup.Id] = true
}
} else if userGroup.Viewers != nil {
if utils.ItemInSlice(groupToCheck, userGroup.Viewers.GroupIds) {
ourGroups[userGroup.Id] = true
}
}
}
}
}
memberOfGroups := utils.GetMapKeys(ourGroups)
// Any time we create a session user, we cache the list of groups it's a member of
// so that HTTP endpoints can also access this and determine permissions properly
cachedUserGroupMembership[userId] = memberOfGroups
return &SessionUser{
SessionId: sessionId,
User: userDBItem.Info,
Permissions: permissions,
MemberOfGroupIds: memberOfGroups,
}, nil
}
func GetCachedUserGroupMembership(userId string) ([]string, bool) {
membership, ok := cachedUserGroupMembership[userId]
return membership, ok
}