From 1ed8283df70c5c2f597821fd318cbda89d2eb7ea Mon Sep 17 00:00:00 2001 From: Thibaut Horel Date: Sat, 29 Dec 2018 19:33:16 -0500 Subject: Add basic user page --- main.go | 64 ++++++++++++++++++++++++++++++++++------------------ store.go | 26 ++++++++++++++------- templates/index.tmpl | 25 ++++++++++++++++++++ utils.go | 13 +++++++++++ 4 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 templates/index.tmpl create mode 100644 utils.go diff --git a/main.go b/main.go index e7718a3..a5de4dc 100644 --- a/main.go +++ b/main.go @@ -1,9 +1,7 @@ package main import ( - "crypto/md5" "crypto/subtle" - "encoding/hex" "flag" "fmt" "html/template" @@ -29,35 +27,50 @@ func logMux(handler http.Handler) http.Handler { }) } -func (app *App) validateHandler(w http.ResponseWriter, r *http.Request) { +func (app *App) validate(r *http.Request) (*Session, bool) { c, err := r.Cookie("id") - //log.Println(r.Header.Get("X-Original-URI")) - //log.Println(r.Host) if err != nil { + return nil, false + } else if s, ok := app.GetSession(c.Value); ok { + return s, true + } else { + return nil, false + } +} + +func (app *App) validateHandler(w http.ResponseWriter, r *http.Request) { + if s, ok := app.validate(r); ok { + w.Header().Set("X-Remote-User", strconv.FormatInt(s.UserId, 10)) + w.WriteHeader(http.StatusOK) + } else { w.WriteHeader(http.StatusUnauthorized) + } +} + +func (app *App) rootHandler(w http.ResponseWriter, r *http.Request) { + if s, ok := app.validate(r); ok { + app.Template.ExecuteTemplate(w, "index.tmpl", s) } else { - if s, ok := app.GetSession(c.Value); ok { - w.Header().Set("X-Remote-User", strconv.FormatInt(s.UserId, 10)) - w.WriteHeader(http.StatusOK) - } else { - log.Println("Session does not exist:", c.Value) - w.WriteHeader(http.StatusUnauthorized) - } + http.Redirect(w, r, "/login", http.StatusSeeOther) } } func (app *App) loginHandler(w http.ResponseWriter, r *http.Request) { - if r.Method == http.MethodPost { + if _, ok := app.validate(r); ok { + http.Redirect(w, r, "/", http.StatusSeeOther) + return + } else if r.Method == http.MethodPost { username := r.FormValue("username") - password := r.FormValue("password") + hash := md5hex([]byte(r.FormValue("password"))) next := r.FormValue("next") - hash := md5.Sum([]byte(password)) - dst := make([]byte, hex.EncodedLen(md5.Size)) - hex.Encode(dst, hash[:]) u, ok := app.GetUser(username) - if ok && subtle.ConstantTimeCompare(u.Password, dst) == 1 { + if ok && subtle.ConstantTimeCompare(u.Password, hash) == 1 { s := app.NewSession(u.Id) - c := http.Cookie{Name: "id", Value: s.Id, Domain: "." + app.Domain} + c := http.Cookie{ + Name: "id", + Value: s.Id, + Domain: "." + app.Domain, + } http.SetCookie(w, &c) http.Redirect(w, r, next, http.StatusSeeOther) } else { @@ -74,13 +87,17 @@ func (app *App) loginHandler(w http.ResponseWriter, r *http.Request) { } func (app *App) logoutHandler(w http.ResponseWriter, r *http.Request) { - c := http.Cookie{Name: "id", Value: "", Domain: "." + app.Domain, MaxAge: 0} + c := http.Cookie{ + Name: "id", + Value: "", + Domain: "." + app.Domain, + MaxAge: 0, + } http.SetCookie(w, &c) http.Redirect(w, r, "/login", http.StatusSeeOther) } func main() { - flag.Usage = func() { fmt.Fprintf( flag.CommandLine.Output(), @@ -99,11 +116,14 @@ func main() { } store := NewPgStore(flag.Args()[0]) - template := template.Must(template.New("").ParseGlob(filepath.Join(*templateDir, "*.tmpl"))) + template := template.Must( + template.New("").ParseGlob(filepath.Join(*templateDir, "*.tmpl")), + ) app := &App{store, template, flag.Args()[1]} http.HandleFunc("/validate", app.validateHandler) http.HandleFunc("/login", app.loginHandler) http.HandleFunc("/logout", app.logoutHandler) + http.HandleFunc("/", app.rootHandler) if err := http.ListenAndServe(*address, logMux(http.DefaultServeMux)); err != nil { panic(err) } diff --git a/store.go b/store.go index 9723b66..89698ea 100644 --- a/store.go +++ b/store.go @@ -3,13 +3,15 @@ package main import ( "database/sql" "log" + "time" _ "github.com/lib/pq" ) type Session struct { - Id string - UserId int64 + Id string + UserId int64 + Created time.Time } type User struct { @@ -43,8 +45,11 @@ func (store *PgStore) GetSession(id string) (*Session, bool) { return s, true } s = new(Session) - row := store.QueryRow("SELECT id, user_id FROM sessions WHERE id = $1", id) - if err := row.Scan(&s.Id, &s.UserId); err != nil { + row := store.QueryRow( + "SELECT id, user_id, created_at FROM sessions WHERE id = $1", + id, + ) + if err := row.Scan(&s.Id, &s.UserId, &s.Created); err != nil { return nil, false } store.sessionCache[s.Id] = s @@ -52,16 +57,21 @@ func (store *PgStore) GetSession(id string) (*Session, bool) { } func (store *PgStore) NewSession(userId int64) *Session { - var id string - store.QueryRow("INSERT INTO sessions(user_id) VALUES ($1) RETURNING id", userId).Scan(&id) - s := &Session{id, userId} + s := &Session{UserId: userId} + store.QueryRow( + "INSERT INTO sessions(user_id) VALUES ($1) RETURNING id, created_at", + userId, + ).Scan(&s.Id, &s.Created) store.sessionCache[s.Id] = s return s } func (store *PgStore) GetUser(name string) (*User, bool) { u := &User{Name: name} - row := store.QueryRow("SELECT id, password FROM users WHERE name = $1", name) + row := store.QueryRow( + "SELECT id, password FROM users WHERE name = $1", + name, + ) if err := row.Scan(&u.Id, &u.Password); err != nil { return nil, false } diff --git a/templates/index.tmpl b/templates/index.tmpl new file mode 100644 index 0000000..8f6a3b9 --- /dev/null +++ b/templates/index.tmpl @@ -0,0 +1,25 @@ + + + + + + + + + + +

Logout

+ +

{{.Id}} {{.Created}}

+ + diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..c123565 --- /dev/null +++ b/utils.go @@ -0,0 +1,13 @@ +package main + +import ( + "crypto/md5" + "encoding/hex" +) + +func md5hex(b []byte) []byte { + hash := md5.Sum(b) + dst := make([]byte, hex.EncodedLen(md5.Size)) + hex.Encode(dst, hash[:]) + return dst +} -- cgit v1.2.3-70-g09d2