Reorganize the store, add a FindAccounts method
This commit is contained in:
@@ -16,7 +16,7 @@ var (
|
|||||||
// type Session implements the User interface for emersion/go-imap
|
// type Session implements the User interface for emersion/go-imap
|
||||||
type Session struct {
|
type Session struct {
|
||||||
ID uint64
|
ID uint64
|
||||||
Account *store.Account
|
Account store.Account
|
||||||
ServiceName string
|
ServiceName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ import (
|
|||||||
// logged-in account per-session
|
// logged-in account per-session
|
||||||
type sender struct {
|
type sender struct {
|
||||||
msa *msa
|
msa *msa
|
||||||
account *store.Account
|
account store.Account
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sender) ServeSMTP(from string, to []string, r io.Reader) error {
|
func (s *sender) ServeSMTP(from string, to []string, r io.Reader) error {
|
||||||
|
@@ -1,18 +1,16 @@
|
|||||||
package store
|
package store
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HashPassword turns a plaintext password into a crypt()ed string, using bcrypt
|
type AccountInterface interface {
|
||||||
func HashPassword(password string) (string, error) {
|
CreateAccount(*Account) error
|
||||||
b, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
FindAccount(string) (Account, error)
|
||||||
|
FindAccounts(...string) ([]Account, error)
|
||||||
return string(b), err
|
FindAccountWithPassword(string, string) (Account, error)
|
||||||
}
|
|
||||||
|
|
||||||
func CheckPassword(hashed, plain string) bool {
|
|
||||||
return bcrypt.CompareHashAndPassword([]byte(hashed), []byte(plain)) == nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account is stored in the database as domains/<domain>/accounts/<id>/config
|
// Account is stored in the database as domains/<domain>/accounts/<id>/config
|
||||||
@@ -32,3 +30,46 @@ type Account struct {
|
|||||||
// As generated by HashPassword
|
// As generated by HashPassword
|
||||||
PasswordHash string
|
PasswordHash string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HashPassword turns a plaintext password into a crypt()ed string, using bcrypt
|
||||||
|
func HashPassword(password string) (string, error) {
|
||||||
|
b, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
|
||||||
|
return string(b), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckPassword(hashed, plain string) bool {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(hashed), []byte(plain)) == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concrete) CreateAccount(account *Account) error {
|
||||||
|
return c.storm.Save(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concrete) FindAccount(username string) (Account, error) {
|
||||||
|
var account Account
|
||||||
|
|
||||||
|
return account, c.storm.One("Username", username, &account)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concrete) FindAccounts(usernames ...string) ([]Account, error) {
|
||||||
|
var accounts []Account
|
||||||
|
|
||||||
|
return accounts, c.storm.Find("Username", usernames, &accounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *concrete) FindAccountWithPassword(username, password string) (Account, error) {
|
||||||
|
account, err := c.FindAccount(username)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Always do a bcrypt check to avoid timing attacks
|
||||||
|
_ = CheckPassword("", "")
|
||||||
|
return Account{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !CheckPassword(account.PasswordHash, password) {
|
||||||
|
return Account{}, fmt.Errorf("bad password")
|
||||||
|
}
|
||||||
|
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
|
@@ -18,9 +18,7 @@ type Interface interface {
|
|||||||
SetDomain(string) error
|
SetDomain(string) error
|
||||||
SetTLS([]byte, []byte) error
|
SetTLS([]byte, []byte) error
|
||||||
|
|
||||||
CreateAccount(*Account) error
|
AccountInterface
|
||||||
FindAccount(string) (*Account, error)
|
|
||||||
FindAccountWithPassword(string, string) (*Account, error)
|
|
||||||
|
|
||||||
io.Closer
|
io.Closer
|
||||||
}
|
}
|
||||||
@@ -142,32 +140,6 @@ func (c *concrete) SetTLS(certPEM, keyPEM []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *concrete) CreateAccount(account *Account) error {
|
|
||||||
return c.storm.Save(account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *concrete) FindAccount(username string) (*Account, error) {
|
|
||||||
var account Account
|
|
||||||
|
|
||||||
return &account, c.storm.One("Username", username, &account)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *concrete) FindAccountWithPassword(username, password string) (*Account, error) {
|
|
||||||
account, err := c.FindAccount(username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
// Always do a bcrypt check to avoid timing attacks
|
|
||||||
_ = CheckPassword("", "")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !CheckPassword(account.PasswordHash, password) {
|
|
||||||
return nil, fmt.Errorf("bad password")
|
|
||||||
}
|
|
||||||
|
|
||||||
return account, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *concrete) Close() error {
|
func (c *concrete) Close() error {
|
||||||
return c.storm.Close()
|
return c.storm.Close()
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user