/
user.go
63 lines (53 loc) · 1.63 KB
/
user.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
package store
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"fmt"
"hash"
"hash/crc64"
"io"
"regexp"
log "github.com/go-pkgz/lgr"
)
// User holds user-related info
type User struct {
Name string `json:"name"`
ID string `json:"id"`
Picture string `json:"picture"`
IP string `json:"ip,omitempty"`
Admin bool `json:"admin"`
Blocked bool `json:"block,omitempty"`
Verified bool `json:"verified,omitempty"`
}
var reValidSha = regexp.MustCompile("^[a-fA-F0-9]{40}$")
var reValidCrc64 = regexp.MustCompile("^[a-fA-F0-9]{16}$")
// HashIP replace IP field with hashed hmac
func (u *User) HashIP(secret string) {
u.IP = HashValue(u.IP, secret)
}
// HashValue makes hmac with secret
func HashValue(val string, secret string) string {
key := []byte(secret)
return hashWithFallback(hmac.New(sha1.New, key), val)
}
// EncodeID hashes id to sha1. The function intentionally left outside of User struct because in some cases
// we need hashing for parts of id, in some others hashing for non-User values.
func EncodeID(id string) string {
return hashWithFallback(sha1.New(), id)
}
// hashWithFallback tries to has val with hash.Hash and fallback to crc if needed
func hashWithFallback(h hash.Hash, val string) string {
if reValidSha.MatchString(val) {
return val // already hashed or empty
}
if _, err := io.WriteString(h, val); err != nil {
// fail back to crc64
log.Printf("[WARN] can't hash id %s, %s", val, err)
if reValidCrc64.MatchString(val) {
return val // already crced
}
return fmt.Sprintf("%x", crc64.Checksum([]byte(val), crc64.MakeTable(crc64.ECMA)))
}
return hex.EncodeToString(h.Sum(nil))
}