package user import ( "crypto/rand" "encoding/base64" "fmt" "time" "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 NewUser(d *db.Database) *User { return &User{ Db: d, } } func (u *User) Insert() error { err := u.Db.InsertTable( "users", []string{"username", "secret", "email"}, db.DbValues{"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 }