-
Notifications
You must be signed in to change notification settings - Fork 0
/
invite_codes.go
145 lines (115 loc) · 3.26 KB
/
invite_codes.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
// Invite codes
package main
import (
"crypto/rand"
"crypto/subtle"
"encoding/hex"
"strings"
"sync"
"time"
)
// Invite code expiration (10 minutes)
const INVITE_CODE_EXPIRATION = 10 * 60 * 1000
// Invite code
type InviteCode struct {
code string // Code
key []byte // Decryption key to create the session
duration int64 // Duration for the session (Milliseconds)
not_after int64 // Invite code expiration (Unix milliseconds)
}
// Invitation Manager
type InvitationManager struct {
vault *Vault // Reference to vault
lock *sync.Mutex // Mutex to access the data
codes map[string]*InviteCode // Mapping user -> code
}
// Initialization
func (im *InvitationManager) Initialize(vault *Vault) {
im.vault = vault
im.lock = &sync.Mutex{}
im.codes = make(map[string]*InviteCode)
}
// Uses an invite code
// code - The invite code
// Returns:
// - success True if successful
// - invitedBy User who created the code
// - key Vault decryption key
// - duration Session duration (milliseconds)
func (im *InvitationManager) UseCode(code string) (success bool, invitedBy string, key []byte, duration int64) {
im.lock.Lock()
defer im.lock.Unlock()
now := time.Now().UnixMilli()
for u, codeData := range im.codes {
if codeData.not_after < now {
continue // Expired code
}
if subtle.ConstantTimeCompare([]byte(codeData.code), []byte(code)) == 1 {
delete(im.codes, u) // Single use
return true, u, codeData.key, codeData.duration
}
}
return false, "", nil, 0
}
// Gets code by user
// user the user
// Returns:
// - has_code True if the user has a code
// - code The code
// - not_after Code expiration timestamp (Unix milliseconds)
// - duration Session duration (milliseconds)
func (im *InvitationManager) GetCodeByUser(user string) (has_code bool, code string, not_after int64, duration int64) {
im.lock.Lock()
defer im.lock.Unlock()
c := im.codes[user]
if c == nil {
return false, "", 0, 0
}
return true, c.code, c.not_after, c.duration
}
// Generates a code for an user
// user - The user
// key - Vault decryption key
// duration - Duration for the invite session
// Returns:
// - code The generated invite code
// - not_after Code expiration (Unix milliseconds)
// - err The error
func (im *InvitationManager) GenerateCode(user string, key []byte, duration int64) (code string, not_after int64, err error) {
codeBytes := make([]byte, 3)
_, err_rand := rand.Read(codeBytes)
if err_rand != nil {
return "", 0, err_rand
}
codeStr := strings.ToUpper(hex.EncodeToString(codeBytes))
codeExpiration := time.Now().UnixMilli() + INVITE_CODE_EXPIRATION
im.lock.Lock()
defer im.lock.Unlock()
im.codes[user] = &InviteCode{
code: codeStr,
key: key,
not_after: codeExpiration,
duration: duration,
}
return codeStr, codeExpiration, nil
}
// Clears user invite code
// user - The user
func (im *InvitationManager) ClearCode(user string) {
im.lock.Lock()
defer im.lock.Unlock()
if im.codes[user] != nil {
delete(im.codes, user)
}
}
// Changes invite code username
// user - Old username
// new_user - New username
func (im *InvitationManager) ChangeUsername(user string, new_user string) {
im.lock.Lock()
defer im.lock.Unlock()
if im.codes[user] != nil {
im.codes[new_user] = im.codes[user]
delete(im.codes, user)
}
}