2021-08-19 00:13:18 +00:00
|
|
|
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.
|
2021-08-31 02:08:51 +00:00
|
|
|
func NewUserIDCalculator(secret []byte) *UserIDCalculator {
|
|
|
|
return &UserIDCalculator{
|
2021-08-19 00:13:18 +00:00
|
|
|
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.
|
2021-08-31 02:08:51 +00:00
|
|
|
func (c *UserIDCalculator) Calculate(name, password string) UserID {
|
2021-08-19 00:13:18 +00:00
|
|
|
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
}
|