package web import ( "net/http" "strconv" "golang.org/x/crypto/bcrypt" "bitmask.me/skeleton/internal/database" "github.com/jmoiron/sqlx" "github.com/pkg/errors" ) // ErrNotImplemented is returned whenever a feature is not implemented yet. var ErrNotImplemented = errors.New("Not implemented") // User interface is provided by all data types that are returned from a // User store. type User interface { GetID() string GetDisplayName() string } // UserRow wraps a user row from the database. type UserRow struct { *database.User } // GetDisplayName implements User interface by returning the display name. func (u UserRow) GetDisplayName() string { return u.GetID() } // GetID implements the User interface by returning the user ID. func (u UserRow) GetID() string { return strconv.FormatInt(u.ID, 10) } // NewAuthenticator returns a authable function from a Database. func NewAuthenticator(db *sqlx.DB) func(user, pass string) (User, error) { return func(user, pass string) (User, error) { // Fetch email used for login email, err := database.EmailByAddress(db, user) if err != nil { return nil, err } row, err := email.User(db) if err != nil { return nil, err } //u.Password err = bcrypt.CompareHashAndPassword(row.Password, []byte(pass)) if err != nil { return nil, err } u := UserRow{row} return u, nil } } // LoginPageHandler renders the login page, and sets session cookies // on successful authentication. func (h *Handlers) LoginPageHandler(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { type LoginForm struct { Login string Password string } loginForm := LoginForm{ Login: r.PostFormValue("login"), Password: r.PostFormValue("password"), } authenticate := NewAuthenticator(h.App.Database()) user, err := authenticate(loginForm.Login, loginForm.Password) if err != nil { context := h.commonRenderContext(r) context["Errors"] = []string{"Wrong username or password"} h.Templates().Get("auth_login.tmpl").Execute(w, context) return } sess := h.Session() sess.Put(r.Context(), SessKeyUserID, user.GetID()) sess.Put(r.Context(), SessKeyUserName, user.GetDisplayName()) http.Redirect(w, r, "/app", http.StatusFound) return } h.Templates().Get("auth_login.tmpl").Execute(w, h.commonRenderContext(r)) }