aboutsummaryrefslogtreecommitdiff
path: root/cmd/web/handlers/login.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/web/handlers/login.go')
-rw-r--r--cmd/web/handlers/login.go170
1 files changed, 170 insertions, 0 deletions
diff --git a/cmd/web/handlers/login.go b/cmd/web/handlers/login.go
new file mode 100644
index 0000000..e867e07
--- /dev/null
+++ b/cmd/web/handlers/login.go
@@ -0,0 +1,170 @@
+package handlers
+
+import (
+ "database/sql"
+ "html/template"
+ "log"
+ "net/http"
+ "os"
+ "time"
+
+ "github.com/google/uuid"
+ "golang.org/x/crypto/bcrypt"
+ "paterissa.net/mblog/internal/models"
+)
+
+type loginContext struct {
+ err *log.Logger
+ db *sql.DB
+}
+
+func (ctx *loginContext) index(w http.ResponseWriter, r *http.Request) {
+ files := []string{
+ "ui/html/base.tmpl.html",
+ "ui/html/login.tmpl.html",
+ "ui/html/music_player.tmpl.html",
+ }
+
+ compiled, err := template.ParseFiles(files...)
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Server Error"))
+ ctx.err.Printf("Failed to parse templates: %v\n", err)
+ return
+ }
+
+ err = compiled.ExecuteTemplate(w, "base", ctx)
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Server Error"))
+ ctx.err.Printf("Failed to parse templates: %v\n", err)
+ return
+ }
+
+ return
+}
+
+func (ctx *loginContext) login(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ w.WriteHeader(405)
+ w.Write([]byte("Method Not Allowed"))
+ return
+ }
+
+ err := r.ParseForm()
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Failed to retrieve form data: %v\n", err)
+ return
+ }
+
+ user := r.PostForm.Get("user")
+ passOne := r.PostForm.Get("pass_one")
+ passTwo := r.PostForm.Get("pass_two")
+
+ stmt, err := ctx.db.Prepare("SELECT * FROM logins WHERE name = $1;")
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Failed to retrieve form data: %v\n", err)
+ return
+ }
+ defer stmt.Close()
+
+ var u models.User
+
+ row := stmt.QueryRow(user)
+ err = row.Scan(&u.Id, &u.Name, &u.Time, &u.PassOne, &u.PassTwo)
+ if err != nil {
+ w.WriteHeader(401)
+ w.Write([]byte("Unauthorized"))
+ ctx.err.Printf("Failed to retrieve user info from DB: %v\n", err)
+ return
+ }
+
+ passOneErr := bcrypt.CompareHashAndPassword([]byte(u.PassOne), []byte(passOne))
+ passTwoErr := bcrypt.CompareHashAndPassword([]byte(u.PassTwo), []byte(passTwo))
+ if passOneErr != nil || passTwoErr != nil {
+ w.WriteHeader(401)
+ w.Write([]byte("Failed to login - not authorized"))
+ return
+ }
+
+ cookie := http.Cookie{
+ Name: "paterissa_session_token",
+ Value: uuid.New().String(),
+ Expires: time.Now().AddDate(0, 0, 1),
+ Path: "/",
+ Domain: os.Getenv("serv"),
+ HttpOnly: true,
+ Secure: true,
+ }
+
+ commit, err := ctx.db.Prepare("INSERT INTO cookies (content, user_id, expiration) VALUES ($1, $2, $3);")
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Failed to prepare DB statement: %v\n", err)
+ return
+ }
+
+ _, err = commit.Exec(cookie.Value, u.Id, cookie.Expires)
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Failed to prepare DB statement: %v\n", err)
+ }
+
+ http.SetCookie(w, &cookie)
+ http.Redirect(w, r, "/", http.StatusFound)
+ return
+}
+
+func (ctx *loginContext) logout(w http.ResponseWriter, r *http.Request) {
+ cookie, err := r.Cookie("paterissa_session_token")
+ if err != nil {
+ w.WriteHeader(405)
+ w.Write([]byte("Unauthorized"))
+ return
+ }
+
+ stmt, err := ctx.db.Prepare("UPDATE cookies SET expiration = $1 WHERE content = $2;")
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not prepare DB statement: %v\n", err)
+ return
+ }
+ defer stmt.Close()
+
+ _, err = stmt.Exec(time.Now(), cookie.Value)
+ if err != nil {
+ w.WriteHeader(500)
+ w.Write([]byte("Internal Error"))
+ ctx.err.Printf("Could not execute DB statement: %v\n", err)
+ return
+ }
+
+ cookie = &http.Cookie{
+ Name: "paterissa_session_token",
+ Value: "",
+ Path: "/",
+ MaxAge: -1,
+ HttpOnly: true,
+ }
+
+ http.SetCookie(w, cookie)
+ http.Redirect(w, r, "/", http.StatusFound)
+ return
+}
+
+func (ctx *loginContext) handle(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "POST" {
+ ctx.index(w, r)
+ return
+ } else {
+ ctx.login(w, r)
+ return
+ }
+}