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
|
package chat
import (
"encoding/hex"
"fmt"
"sync"
"golang.org/x/crypto/argon2"
)
// UserID uniquely identifies an individual user who has posted a message in a
// Room.
type UserID struct {
// Name will be the user's chosen display name.
Name string `json:"name"`
// Hash will be a hex string generated from a secret only the user knows.
Hash string `json:"id"`
}
// UserIDCalculator is used to calculate UserIDs.
type UserIDCalculator struct {
// Secret is used when calculating UserID Hash salts.
Secret []byte
// TimeCost, MemoryCost, and Threads are used as inputs to the Argon2id
// algorithm which is used to generate the Hash.
TimeCost, MemoryCost uint32
Threads uint8
// HashLen specifies the number of bytes the Hash should be.
HashLen uint32
// Lock, if set, forces concurrent Calculate calls to occur sequentially.
Lock *sync.Mutex
}
// NewUserIDCalculator returns a UserIDCalculator with sane defaults.
func NewUserIDCalculator(secret []byte) *UserIDCalculator {
return &UserIDCalculator{
Secret: secret,
TimeCost: 15,
MemoryCost: 128 * 1024,
Threads: 2,
HashLen: 16,
Lock: new(sync.Mutex),
}
}
// Calculate accepts a name and password and returns the calculated UserID.
func (c *UserIDCalculator) Calculate(name, password string) UserID {
input := fmt.Sprintf("%q:%q", name, password)
hashB := argon2.IDKey(
[]byte(input),
c.Secret, // salt
c.TimeCost, c.MemoryCost, c.Threads,
c.HashLen,
)
return UserID{
Name: name,
Hash: hex.EncodeToString(hashB),
}
}
|