aboutsummaryrefslogtreecommitdiff
path: root/src/user/user.go
blob: e35c7c5d53b802ae59175b9502e37a742d0f294c (plain)
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
package user

import (
	"crypto/rand"
	"encoding/base64"
	"fmt"
	"time"

	"github.com/jackc/pgx/v5"
	"gitlab.com/alexkavon/newsstand/src/db"
	"golang.org/x/crypto/argon2"
)

type User struct {
	Id        int64
	Username  string `validate:"required,max=50"`
	Secret    string `validate:"required,min=8,max=128"`
	Email     string `validate:"required,email"`
	Karma     uint64
	UpdatedAt time.Time
	CreatedAt time.Time
	hash      string
	Db        *db.Database
}

func (u *User) Insert() error {
	err := u.Db.InsertTable(
		"users",
		[]string{"username", "secret", "email"},
		pgx.NamedArgs{"username": u.Username, "secret": string(u.hash), "email": u.Email},
	)
	if err != nil {
		return err
	}
	return nil
}

func (u *User) HashSecret() error {
	hashconf := &struct {
		memory      uint32
		iterations  uint32
		parallelism uint8
		keyLength   uint32
		saltLength  uint32
	}{64 * 1024, 3, 2, 12, 16}
	salt := make([]byte, hashconf.saltLength)
	_, err := rand.Read(salt)
	if err != nil {
		return err
	}

	hash := argon2.IDKey(
		[]byte(u.Secret),
		salt,
		hashconf.iterations,
		hashconf.memory,
		hashconf.parallelism,
		hashconf.keyLength,
	)
	b64Salt := base64.RawStdEncoding.EncodeToString(salt)
	b64Hash := base64.RawStdEncoding.EncodeToString(hash)
	encodedHash := fmt.Sprintf(
		"$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s",
		argon2.Version,
		hashconf.memory,
		hashconf.iterations,
		hashconf.parallelism,
		b64Salt,
		b64Hash,
	)
	u.hash = encodedHash
	return nil
}