101 lines
1.6 KiB
Go
101 lines
1.6 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type User struct {
|
|
Username string `json:"username"`
|
|
HashedPassword []byte `json:"hashed_password"`
|
|
IsAdmin bool `json:"is_admin"`
|
|
}
|
|
|
|
func (u *User) SetPassword(password string) error {
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
u.HashedPassword = hash
|
|
|
|
return nil
|
|
}
|
|
|
|
func (u *User) VerifyPassword(password string) error {
|
|
return bcrypt.CompareHashAndPassword([]byte(u.HashedPassword), []byte(password))
|
|
}
|
|
|
|
type UserStore struct {
|
|
users map[string]*User
|
|
}
|
|
|
|
func NewUserStore() *UserStore {
|
|
return &UserStore{
|
|
users: make(map[string]*User),
|
|
}
|
|
}
|
|
|
|
var ErrNoSuchUser = fmt.Errorf("no such user")
|
|
|
|
func (s *UserStore) Put(u *User) error {
|
|
s.users[u.Username] = u
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *UserStore) Get(username string) (*User, error) {
|
|
u, ok := s.users[username]
|
|
if !ok {
|
|
return nil, ErrNoSuchUser
|
|
}
|
|
|
|
return u, nil
|
|
}
|
|
|
|
func (s *UserStore) ToWriter(w io.Writer) error {
|
|
enc := json.NewEncoder(w)
|
|
|
|
if err := enc.Encode(&s.users); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *UserStore) ToFile(path string) error {
|
|
f, err := os.Create(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
return s.ToWriter(f)
|
|
}
|
|
|
|
func StoreFromReader(r io.Reader) (*UserStore, error) {
|
|
dec := json.NewDecoder(r)
|
|
|
|
s := &UserStore{}
|
|
|
|
if err := dec.Decode(&s.users); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func StoreFromFile(path string) (*UserStore, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
|
|
return StoreFromReader(f)
|
|
}
|