parent
b5dca6fa53
commit
f380f94043
@ -0,0 +1,237 @@ |
||||
package web |
||||
|
||||
import ( |
||||
"h4kor/owl-blogs" |
||||
"net/http" |
||||
"time" |
||||
|
||||
"github.com/julienschmidt/httprouter" |
||||
) |
||||
|
||||
func isUserLoggedIn(user *owl.User, r *http.Request) bool { |
||||
sessionCookie, err := r.Cookie("session") |
||||
if err != nil { |
||||
return false |
||||
} |
||||
return user.ValidateSession(sessionCookie.Value) |
||||
} |
||||
|
||||
func setCSRFCookie(w http.ResponseWriter) string { |
||||
csrfToken := owl.GenerateRandomString(32) |
||||
cookie := http.Cookie{ |
||||
Name: "csrf_token", |
||||
Value: csrfToken, |
||||
HttpOnly: true, |
||||
SameSite: http.SameSiteStrictMode, |
||||
} |
||||
http.SetCookie(w, &cookie) |
||||
return csrfToken |
||||
} |
||||
|
||||
func checkCSRF(r *http.Request) bool { |
||||
// CSRF check
|
||||
formCsrfToken := r.FormValue("csrf_token") |
||||
cookieCsrfToken, err := r.Cookie("csrf_token") |
||||
|
||||
if err != nil { |
||||
println("Error getting csrf token from cookie: ", err.Error()) |
||||
return false |
||||
} |
||||
if formCsrfToken != cookieCsrfToken.Value { |
||||
println("Invalid csrf token") |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func userLoginGetHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, httprouter.Params) { |
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { |
||||
user, err := getUserFromRepo(repo, ps) |
||||
if err != nil { |
||||
println("Error getting user: ", err.Error()) |
||||
notFoundHandler(repo)(w, r) |
||||
return |
||||
} |
||||
|
||||
if isUserLoggedIn(&user, r) { |
||||
http.Redirect(w, r, user.EditorUrl(), http.StatusFound) |
||||
return |
||||
} |
||||
csrfToken := setCSRFCookie(w) |
||||
html, err := owl.RenderLoginPage(user, csrfToken) |
||||
if err != nil { |
||||
println("Error rendering login page: ", err.Error()) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "Internal server error", |
||||
Message: "Internal server error", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
w.Write([]byte(html)) |
||||
} |
||||
} |
||||
|
||||
func userLoginPostHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, httprouter.Params) { |
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { |
||||
user, err := getUserFromRepo(repo, ps) |
||||
if err != nil { |
||||
println("Error getting user: ", err.Error()) |
||||
notFoundHandler(repo)(w, r) |
||||
return |
||||
} |
||||
err = r.ParseForm() |
||||
if err != nil { |
||||
println("Error parsing form: ", err.Error()) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "Internal server error", |
||||
Message: "Internal server error", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
|
||||
// CSRF check
|
||||
if !checkCSRF(r) { |
||||
w.WriteHeader(http.StatusBadRequest) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "CSRF Error", |
||||
Message: "Invalid csrf token", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
|
||||
password := r.Form.Get("password") |
||||
if password == "" { |
||||
userLoginGetHandler(repo)(w, r, ps) |
||||
return |
||||
} |
||||
if !user.VerifyPassword(password) { |
||||
userLoginGetHandler(repo)(w, r, ps) |
||||
return |
||||
} |
||||
|
||||
// set session cookie
|
||||
cookie := http.Cookie{ |
||||
Name: "session", |
||||
Value: user.CreateNewSession(), |
||||
Path: "/", |
||||
Expires: time.Now().Add(30 * 24 * time.Hour), |
||||
HttpOnly: true, |
||||
} |
||||
http.SetCookie(w, &cookie) |
||||
http.Redirect(w, r, user.EditorUrl(), http.StatusFound) |
||||
} |
||||
} |
||||
|
||||
func userEditorGetHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, httprouter.Params) { |
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { |
||||
user, err := getUserFromRepo(repo, ps) |
||||
if err != nil { |
||||
println("Error getting user: ", err.Error()) |
||||
notFoundHandler(repo)(w, r) |
||||
return |
||||
} |
||||
|
||||
if !isUserLoggedIn(&user, r) { |
||||
http.Redirect(w, r, user.EditorLoginUrl(), http.StatusFound) |
||||
return |
||||
} |
||||
|
||||
csrfToken := setCSRFCookie(w) |
||||
html, err := owl.RenderEditorPage(user, csrfToken) |
||||
if err != nil { |
||||
println("Error rendering editor page: ", err.Error()) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "Internal server error", |
||||
Message: "Internal server error", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
w.Write([]byte(html)) |
||||
} |
||||
} |
||||
|
||||
func userEditorPostHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, httprouter.Params) { |
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { |
||||
user, err := getUserFromRepo(repo, ps) |
||||
if err != nil { |
||||
println("Error getting user: ", err.Error()) |
||||
notFoundHandler(repo)(w, r) |
||||
return |
||||
} |
||||
|
||||
if !isUserLoggedIn(&user, r) { |
||||
http.Redirect(w, r, user.EditorLoginUrl(), http.StatusFound) |
||||
return |
||||
} |
||||
|
||||
err = r.ParseForm() |
||||
if err != nil { |
||||
println("Error parsing form: ", err.Error()) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "Internal server error", |
||||
Message: "Internal server error", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
|
||||
// CSRF check
|
||||
if !checkCSRF(r) { |
||||
w.WriteHeader(http.StatusBadRequest) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "CSRF Error", |
||||
Message: "Invalid csrf token", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
|
||||
// get form values
|
||||
post_type := r.Form.Get("type") |
||||
title := r.Form.Get("title") |
||||
description := r.Form.Get("description") |
||||
content := r.Form.Get("content") |
||||
draft := r.Form.Get("draft") |
||||
|
||||
// validate form values
|
||||
if post_type == "article" && title == "" { |
||||
userEditorGetHandler(repo)(w, r, ps) |
||||
return |
||||
} |
||||
|
||||
// create post
|
||||
post, err := user.CreateNewPostFull(owl.PostMeta{ |
||||
Type: post_type, |
||||
Title: title, |
||||
Description: description, |
||||
Draft: draft == "on", |
||||
Date: time.Now(), |
||||
}, content) |
||||
|
||||
if err != nil { |
||||
println("Error creating post: ", err.Error()) |
||||
w.WriteHeader(http.StatusInternalServerError) |
||||
html, _ := owl.RenderUserError(user, owl.ErrorMessage{ |
||||
Error: "Internal server error", |
||||
Message: "Internal server error", |
||||
}) |
||||
w.Write([]byte(html)) |
||||
return |
||||
} |
||||
|
||||
// redirect to post
|
||||
if !post.Meta().Draft { |
||||
http.Redirect(w, r, post.FullUrl(), http.StatusFound) |
||||
} else { |
||||
http.Redirect(w, r, user.EditorUrl(), http.StatusFound) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,23 @@ |
||||
<details> |
||||
<summary>Write Article</summary> |
||||
<form action="" method="post"> |
||||
<h2>Create New Article</h2> |
||||
<input type="hidden" name="csrf_token" value="{{.CsrfToken}}"> |
||||
<input type="hidden" name="type" value="article"> |
||||
<label for="title">Title</label> |
||||
<input type="text" name="title" placeholder="Title" /> |
||||
<label for="description">Description</label> |
||||
<input type="text" name="description" placeholder="Description" /> |
||||
<label for="content">Content</label> |
||||
<textarea name="content" placeholder="Content" rows="24"></textarea> |
||||
<input type="checkbox" name="draft" /> |
||||
<label for="draft">Draft</label> |
||||
<br><br> |
||||
<input type="submit" value="Create" /> |
||||
</form> |
||||
</details> |
||||
|
||||
<details> |
||||
<summary>Write Note</summary> |
||||
TODO |
||||
</details> |
@ -0,0 +1,6 @@ |
||||
<form action="" method="post"> |
||||
<h2>Login to Editor</h2> |
||||
<input type="hidden" name="csrf_token" value="{{.CsrfToken}}"> |
||||
<input type="password" name="password" /> |
||||
<input type="submit" value="Login" /> |
||||
</form> |
Loading…
Reference in new issue