diff --git a/cmd/owl/web/auth_handler.go b/cmd/owl/web/auth_handler.go index 1c15a2c..1dabdea 100644 --- a/cmd/owl/web/auth_handler.go +++ b/cmd/owl/web/auth_handler.go @@ -79,33 +79,53 @@ func userAuthHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Reque } if len(missing_params) > 0 { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte(fmt.Sprintf("Missing parameters: %s", strings.Join(missing_params, ", ")))) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Missing parameters", + Message: "Missing parameters: " + strings.Join(missing_params, ", "), + }) + w.Write([]byte(html)) return } - if responseType != "id" { + if responseType == "id" { responseType = "code" } if responseType != "code" { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid response_type. Must be 'code' ('id' converted to 'code' for legacy support).")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Invalid response_type", + Message: "Must be 'code' ('id' converted to 'code' for legacy support).", + }) + w.Write([]byte(html)) return } if codeChallengeMethod != "" && (codeChallengeMethod != "S256" && codeChallengeMethod != "plain") { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid code_challenge_method. Must be 'S256' or 'plain'.")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Invalid code_challenge_method", + Message: "Must be 'S256' or 'plain'.", + }) + w.Write([]byte(html)) return } client_id_url, err := url.Parse(clientId) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid client_id.")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Invalid client_id", + Message: "Invalid client_id: " + clientId, + }) + w.Write([]byte(html)) return } redirect_uri_url, err := url.Parse(redirectUri) if err != nil { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid redirect_uri.")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Invalid redirect_uri", + Message: "Invalid redirect_uri: " + redirectUri, + }) + w.Write([]byte(html)) return } if client_id_url.Host != redirect_uri_url.Host || client_id_url.Scheme != redirect_uri_url.Scheme { @@ -122,7 +142,11 @@ func userAuthHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Reque } if !is_registered { w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid redirect_uri. Must be registered with client_id.")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Invalid redirect_uri", + Message: redirectUri + " is not registered for " + clientId, + }) + w.Write([]byte(html)) return } } @@ -155,10 +179,13 @@ func userAuthHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Reque if err != nil { println("Error rendering auth page: ", err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Internal server error")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Internal Server Error", + Message: "Internal Server Error", + }) + w.Write([]byte(html)) return } - println("Rendering auth page for user", user.Name()) w.Write([]byte(html)) } } @@ -292,7 +319,11 @@ func userAuthVerifyHandler(repo *owl.Repository) func(http.ResponseWriter, *http if err != nil { println("Error parsing form: ", err.Error()) w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Error parsing form")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Error parsing form", + Message: "Error parsing form", + }) + w.Write([]byte(html)) return } password := r.FormValue("password") @@ -311,13 +342,21 @@ func userAuthVerifyHandler(repo *owl.Repository) func(http.ResponseWriter, *http if err != nil { println("Error getting csrf token from cookie: ", err.Error()) w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Error getting csrf token from cookie")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "CSRF Error", + Message: "Error getting csrf token from cookie", + }) + w.Write([]byte(html)) return } if formCsrfToken != cookieCsrfToken.Value { println("Invalid csrf token") w.WriteHeader(http.StatusBadRequest) - w.Write([]byte("Invalid csrf token")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "CSRF Error", + Message: "Invalid csrf token", + }) + w.Write([]byte(html)) return } @@ -342,7 +381,11 @@ func userAuthVerifyHandler(repo *owl.Repository) func(http.ResponseWriter, *http if err != nil { println("Error generating code: ", err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Internal server error")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Internal Server Error", + Message: "Error generating code", + }) + w.Write([]byte(html)) return } http.Redirect(w, r, diff --git a/cmd/owl/web/handler.go b/cmd/owl/web/handler.go index c835c4c..4c5a160 100644 --- a/cmd/owl/web/handler.go +++ b/cmd/owl/web/handler.go @@ -51,7 +51,11 @@ func userIndexHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Requ if err != nil { println("Error rendering index page: ", err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Internal server error")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Internal server error", + Message: "Internal server error", + }) + w.Write([]byte(html)) return } println("Rendering index page for user", user.Name()) @@ -163,7 +167,11 @@ func userRSSHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Reques if err != nil { println("Error rendering index page: ", err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Internal server error")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Internal server error", + Message: "Internal server error", + }) + w.Write([]byte(html)) return } println("Rendering index page for user", user.Name()) @@ -186,14 +194,14 @@ func postHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, if err != nil { println("Error getting post: ", err.Error()) - notFoundHandler(repo)(w, r) + notFoundUserHandler(repo, user)(w, r) return } meta := post.Meta() if meta.Draft { println("Post is a draft") - notFoundHandler(repo)(w, r) + notFoundUserHandler(repo, user)(w, r) return } @@ -201,7 +209,11 @@ func postHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Request, if err != nil { println("Error rendering post: ", err.Error()) w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("Internal server error")) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Internal server error", + Message: "Internal server error", + }) + w.Write([]byte(html)) return } println("Rendering post", postId) @@ -224,13 +236,13 @@ func postMediaHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Requ post, err := user.GetPost(postId) if err != nil { println("Error getting post: ", err.Error()) - notFoundHandler(repo)(w, r) + notFoundUserHandler(repo, user)(w, r) return } filepath = path.Join(post.MediaDir(), filepath) if _, err := os.Stat(filepath); err != nil { println("Error getting file: ", err.Error()) - notFoundHandler(repo)(w, r) + notFoundUserHandler(repo, user)(w, r) return } http.ServeFile(w, r, filepath) @@ -250,7 +262,7 @@ func userMediaHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Requ filepath = path.Join(user.MediaDir(), filepath) if _, err := os.Stat(filepath); err != nil { println("Error getting file: ", err.Error()) - notFoundHandler(repo)(w, r) + notFoundUserHandler(repo, user)(w, r) return } http.ServeFile(w, r, filepath) @@ -269,3 +281,20 @@ func notFoundHandler(repo *owl.Repository) func(http.ResponseWriter, *http.Reque w.Write([]byte("Not found")) } } + +func notFoundUserHandler(repo *owl.Repository, user owl.User) func(http.ResponseWriter, *http.Request) { + return func(w http.ResponseWriter, r *http.Request) { + path := r.URL.Path + aliases, _ := repo.PostAliases() + if _, ok := aliases[path]; ok { + http.Redirect(w, r, aliases[path].UrlPath(), http.StatusMovedPermanently) + return + } + w.WriteHeader(http.StatusNotFound) + html, _ := owl.RenderUserError(user, owl.ErrorMessage{ + Error: "Not found", + Message: "The page you requested could not be found", + }) + w.Write([]byte(html)) + } +} diff --git a/embed/error.html b/embed/error.html new file mode 100644 index 0000000..e3000ab --- /dev/null +++ b/embed/error.html @@ -0,0 +1,4 @@ +
+

{{ .Error }}

+ {{ .Message }} +
\ No newline at end of file diff --git a/renderer.go b/renderer.go index 3ef6df9..1ef0ad2 100644 --- a/renderer.go +++ b/renderer.go @@ -35,6 +35,11 @@ type AuthRequestData struct { CsrfToken string } +type ErrorMessage struct { + Error string + Message string +} + func renderEmbedTemplate(templateFile string, data interface{}) (string, error) { templateStr, err := embed_files.ReadFile(templateFile) if err != nil { @@ -80,9 +85,8 @@ func renderIntoBaseTemplate(user User, data PageContent) (string, error) { } var html bytes.Buffer - t.Execute(&html, full_data) - - return html.String(), nil + err = t.Execute(&html, full_data) + return html.String(), err } func renderPostContent(post *Post) (string, error) { @@ -137,6 +141,18 @@ func RenderUserAuthPage(reqData AuthRequestData) (string, error) { }) } +func RenderUserError(user User, error ErrorMessage) (string, error) { + errHtml, err := renderEmbedTemplate("embed/error.html", error) + if err != nil { + return "", err + } + + return renderIntoBaseTemplate(user, PageContent{ + Title: "Error", + Content: template.HTML(errHtml), + }) +} + func RenderUserList(repo Repository) (string, error) { baseTemplate, _ := repo.Template() users, _ := repo.Users()