aboutsummaryrefslogtreecommitdiff
path: root/cmd/web/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/web/handlers')
-rw-r--r--cmd/web/handlers/blog.go9
-rw-r--r--cmd/web/handlers/login.go170
-rw-r--r--cmd/web/handlers/routes.go13
3 files changed, 191 insertions, 1 deletions
diff --git a/cmd/web/handlers/blog.go b/cmd/web/handlers/blog.go
index bd2d97f..573e52f 100644
--- a/cmd/web/handlers/blog.go
+++ b/cmd/web/handlers/blog.go
@@ -15,22 +15,29 @@ type blogContext struct {
Rows []models.Post
Name string
+ IsAuth bool
}
func (ctx *blogContext) index(w http.ResponseWriter, r *http.Request) {
ctx.Rows = []models.Post{}
+ ctx.IsAuth = false
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
+
+ _, err := r.Cookie("paterissa_session_token")
+ if err == nil {
+ ctx.IsAuth = true;
+ }
offset := r.URL.Query().Get("offset")
if offset == "" {
offset = "20"
}
- rows, err := ctx.db.Query("SELECT * FROM posts WHERE id < " + offset + " ORDER BY id DESC LIMIT 20;")
+ rows, err := ctx.db.Query("SELECT p.id, u.name, p.time, p.content FROM posts p INNER JOIN logins u ON p.user_id = u.id WHERE p.id < " + offset + " ORDER BY p.id DESC LIMIT 20;")
if err != nil {
ctx.err.Print(err.Error())
http.Error(w, "Internal Server Error", 500)
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
+ }
+}
diff --git a/cmd/web/handlers/routes.go b/cmd/web/handlers/routes.go
index e9fd0f5..0196331 100644
--- a/cmd/web/handlers/routes.go
+++ b/cmd/web/handlers/routes.go
@@ -4,15 +4,25 @@ import (
"database/sql"
"net/http"
+ "paterissa.net/mblog/cmd/web/middleware"
"paterissa.net/mblog/cmd/web/types"
)
func RegisterEndpoints(app types.Application, db *sql.DB) *http.ServeMux {
+ auth := middleware.AuthMiddleware{
+ Err: app.Err,
+ Db: db,
+ }
+
blog := blogContext{
err: app.Err,
db: db,
Name: app.Env.Webmaster,
}
+ login := loginContext{
+ err: app.Err,
+ db: db,
+ }
audio := fsContext{
err: app.Err,
path: app.AudioDir,
@@ -26,6 +36,9 @@ func RegisterEndpoints(app types.Application, db *sql.DB) *http.ServeMux {
blogRouter := http.NewServeMux()
blogRouter.HandleFunc("/", blog.index)
+ blogRouter.HandleFunc("/login", login.handle)
+ blogRouter.HandleFunc("/logout", auth.Resolve(login.logout))
+
blogRouter.HandleFunc("/audio", audio.readdir)
blogRouter.HandleFunc("/audio/get", audio.get)