starting accounts #2
11 changed files with 69 additions and 5 deletions
|
@ -19,7 +19,7 @@ func NewController(service domain.AccountService) Controller {
|
||||||
return Controller{service: service}
|
return Controller{service: service}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) Login(w *core.Response, r *http.Request) {
|
func (c Controller) Login(w *core.Response, r *http.Request) {
|
||||||
var request LoginAccountRequest
|
var request LoginAccountRequest
|
||||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||||
w.WriteError(core.ErrInvalidStruct)
|
w.WriteError(core.ErrInvalidStruct)
|
||||||
|
@ -30,4 +30,5 @@ func (c *Controller) Login(w *core.Response, r *http.Request) {
|
||||||
w.WriteError(core.ErrInvalidStruct)
|
w.WriteError(core.ErrInvalidStruct)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,14 @@ type Account struct {
|
||||||
CreatedAt string `db:"created_at" json:"created_at"`
|
CreatedAt string `db:"created_at" json:"created_at"`
|
||||||
UpdatedAt string `db:"updated_at" json:"updated_at"`
|
UpdatedAt string `db:"updated_at" json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AccountLogin struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccountCreate struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
RoleId int
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
type AccountRepository interface {
|
type AccountRepository interface {
|
||||||
Insert(account *Account) (int, error)
|
Insert(account Account) (int, error)
|
||||||
FetchOneByUsername(username string) (*Account, error)
|
FetchOneByUsername(username string) (*Account, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
|
import "gitea.qpismont.fr/qpismont/trepa/internal/core"
|
||||||
|
|
||||||
type AccountService interface {
|
type AccountService interface {
|
||||||
|
Login(login AccountLogin) (*Account, *core.HTTPError)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ func NewRepository(db *sqlx.DB) domain.AccountRepository {
|
||||||
return &Repository{db: db}
|
return &Repository{db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) Insert(account *domain.Account) (int, error) {
|
func (r *Repository) Insert(account domain.Account) (int, error) {
|
||||||
var id int
|
var id int
|
||||||
|
|
||||||
stmt, err := r.db.Prepare(SqlInsert)
|
stmt, err := r.db.Prepare(SqlInsert)
|
||||||
|
|
|
@ -14,7 +14,7 @@ func TestRepository_Insert(t *testing.T) {
|
||||||
|
|
||||||
repo := NewRepository(db)
|
repo := NewRepository(db)
|
||||||
|
|
||||||
account := &domain.Account{
|
account := domain.Account{
|
||||||
Username: "test",
|
Username: "test",
|
||||||
Password: "test",
|
Password: "test",
|
||||||
RoleId: 1,
|
RoleId: 1,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import "gitea.qpismont.fr/qpismont/trepa/internal/accounts/domain"
|
import (
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/accounts/domain"
|
||||||
|
"gitea.qpismont.fr/qpismont/trepa/internal/core"
|
||||||
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
repository domain.AccountRepository
|
repository domain.AccountRepository
|
||||||
|
@ -9,3 +12,16 @@ type Service struct {
|
||||||
func NewService(repository domain.AccountRepository) domain.AccountService {
|
func NewService(repository domain.AccountRepository) domain.AccountService {
|
||||||
return &Service{repository: repository}
|
return &Service{repository: repository}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) Login(login domain.AccountLogin) (*domain.Account, *core.HTTPError) {
|
||||||
|
account, err := s.repository.FetchOneByUsername(login.Username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, domain.ErrAccountNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if !core.ComparePassword(login.Password, account.Password) {
|
||||||
|
return nil, domain.ErrBadPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
|
|
12
internal/core/hash.go
Normal file
12
internal/core/hash.go
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import "golang.org/x/crypto/argon2"
|
||||||
|
|
||||||
|
func HashPassword(password string) string {
|
||||||
|
return string(argon2.IDKey([]byte(password), nil, 1, 64*1024, 4, 32))
|
||||||
|
}
|
||||||
|
|
||||||
|
func ComparePassword(password string, hash string) bool {
|
||||||
|
hashedPassword := HashPassword(password)
|
||||||
|
return hashedPassword == hash
|
||||||
|
}
|
21
internal/core/hash_test.go
Normal file
21
internal/core/hash_test.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHashPassword(t *testing.T) {
|
||||||
|
password := "password"
|
||||||
|
hashedPassword := HashPassword(password)
|
||||||
|
assert.NotEmpty(t, hashedPassword)
|
||||||
|
t.Log(hashedPassword)
|
||||||
|
assert.Equal(t, hashedPassword, "LOLPASSWORD")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestComparePassword(t *testing.T) {
|
||||||
|
password := "password"
|
||||||
|
hashedPassword := HashPassword(password)
|
||||||
|
assert.True(t, ComparePassword(password, hashedPassword))
|
||||||
|
}
|
Loading…
Reference in a new issue