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) }