Add password hashing with argon2
This commit is contained in:
parent
01da46b81e
commit
1dd0332bc1
11 changed files with 107 additions and 15 deletions
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
func Run() {
|
||||
s := store.OpenStore("./foo.db")
|
||||
s.AddUser("admin", "secret")
|
||||
defer s.Close()
|
||||
h := server.New(s)
|
||||
defer h.Close()
|
||||
|
|
|
|||
5
go.mod
5
go.mod
|
|
@ -3,3 +3,8 @@ module github.com/Bronku/iroon
|
|||
go 1.23.5
|
||||
|
||||
require github.com/mattn/go-sqlite3 v1.14.24
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.36.0
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
)
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -1,2 +1,6 @@
|
|||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
package auth
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/Bronku/iroon/internal/crypto"
|
||||
)
|
||||
|
||||
func (a *Authenticator) verifyCredentials(login, password string) error {
|
||||
|
||||
if login == "admin" && password == "secret" {
|
||||
user, ok := a.s.GetUser(login)
|
||||
if !ok {
|
||||
return errors.New("user with this login doesn't exist")
|
||||
}
|
||||
hash := crypto.PasswordHash(password, user.Salt)
|
||||
if hash == user.Password {
|
||||
return nil
|
||||
}
|
||||
return errors.New("wrong credentials")
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/Bronku/iroon/internal/crypto"
|
||||
"github.com/Bronku/iroon/internal/models"
|
||||
)
|
||||
|
||||
func (a *Authenticator) newSession(user string) (http.Cookie, error) {
|
||||
key := generateKey()
|
||||
key := crypto.GenerateKey()
|
||||
var session models.Token
|
||||
var cookie http.Cookie
|
||||
session.User = user
|
||||
|
|
@ -30,11 +28,3 @@ func (a *Authenticator) newSession(user string) (http.Cookie, error) {
|
|||
//cookie.Secure = true
|
||||
return cookie, nil
|
||||
}
|
||||
|
||||
func generateKey() string {
|
||||
key := [32]byte{}
|
||||
if _, err := rand.Read(key[:]); err != nil {
|
||||
log.Fatal("can't generate a vaild key", err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(key[:])
|
||||
}
|
||||
|
|
|
|||
21
internal/crypto/crypto.go
Normal file
21
internal/crypto/crypto.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"log"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
|
||||
func PasswordHash(password, salt string) string {
|
||||
return string(argon2.Key([]byte(password), []byte(salt), 3, 32*1024, 4, 32))
|
||||
}
|
||||
|
||||
func GenerateKey() string {
|
||||
key := [32]byte{}
|
||||
if _, err := rand.Read(key[:]); err != nil {
|
||||
log.Fatal("can't generate a vaild key", err)
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(key[:])
|
||||
}
|
||||
6
internal/models/user.go
Normal file
6
internal/models/user.go
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
package models
|
||||
|
||||
type User struct {
|
||||
Password string
|
||||
Salt string
|
||||
}
|
||||
4
internal/store/migrations/8.sql
Normal file
4
internal/store/migrations/8.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
alter table user
|
||||
add column salt text;
|
||||
|
||||
pragma user_version = 8;
|
||||
|
|
@ -11,6 +11,7 @@ import (
|
|||
type Store struct {
|
||||
db *sql.DB
|
||||
cakes []models.Cake
|
||||
users map[string]models.User
|
||||
}
|
||||
|
||||
func OpenStore(filename string) *Store {
|
||||
|
|
@ -27,6 +28,10 @@ func OpenStore(filename string) *Store {
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
out.users, err = out.loadUsers()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
|
|
|
|||
48
internal/store/user.go
Normal file
48
internal/store/user.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/Bronku/iroon/internal/crypto"
|
||||
"github.com/Bronku/iroon/internal/models"
|
||||
)
|
||||
|
||||
func (s *Store) AddUser(login, password string) error {
|
||||
_, exists := s.GetUser(login)
|
||||
if exists {
|
||||
return errors.New("the user already exists")
|
||||
}
|
||||
query := "insert into user (login, password, salt) values(?, ?, ?)"
|
||||
salt := crypto.GenerateKey()
|
||||
hash := crypto.PasswordHash(password, salt)
|
||||
_, err := s.db.Exec(query, login, hash, salt)
|
||||
if err == nil {
|
||||
s.users[login] = models.User{Password: hash, Salt: salt}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) loadUsers() (map[string]models.User, error) {
|
||||
out := make(map[string]models.User)
|
||||
query := "select login, password, salt from user;"
|
||||
rows, err := s.db.Query(query)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var current models.User
|
||||
var login string
|
||||
err = rows.Scan(&login, ¤t.Password, ¤t.Salt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out[login] = current
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetUser(login string) (models.User, bool) {
|
||||
value, ok := s.users[login]
|
||||
return value, ok
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue