258 lines
7.8 KiB
Go
258 lines
7.8 KiB
Go
package utils
|
|
|
|
import (
|
|
"math/rand"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
// ErrorPageConfig holds configuration for generating error pages
|
|
type ErrorPageConfig struct {
|
|
OverrideDir string // Directory where override templates are stored
|
|
DebugMode bool // Whether to show debug information
|
|
}
|
|
|
|
// ErrorType represents HTTP error types
|
|
type ErrorType int
|
|
|
|
const (
|
|
ErrorTypeNotFound ErrorType = 404
|
|
ErrorTypeMethodNotAllowed ErrorType = 405
|
|
ErrorTypeInternalError ErrorType = 500
|
|
ErrorTypeForbidden ErrorType = 403 // Added CSRF/Forbidden error type
|
|
)
|
|
|
|
// ErrorPage generates an HTML error page based on the error type
|
|
// It first checks for an override file, and if not found, generates a default page
|
|
func ErrorPage(config ErrorPageConfig, errorType ErrorType, url string, errMsg string) string {
|
|
// Check for override file
|
|
if config.OverrideDir != "" {
|
|
var filename string
|
|
switch errorType {
|
|
case ErrorTypeNotFound:
|
|
filename = "404.html"
|
|
case ErrorTypeMethodNotAllowed:
|
|
filename = "405.html"
|
|
case ErrorTypeInternalError:
|
|
filename = "500.html"
|
|
case ErrorTypeForbidden:
|
|
filename = "403.html"
|
|
}
|
|
|
|
if filename != "" {
|
|
overridePath := filepath.Join(config.OverrideDir, filename)
|
|
if content, err := os.ReadFile(overridePath); err == nil {
|
|
return string(content)
|
|
}
|
|
}
|
|
}
|
|
|
|
// No override found, generate default page
|
|
switch errorType {
|
|
case ErrorTypeNotFound:
|
|
return generateNotFoundHTML(url)
|
|
case ErrorTypeMethodNotAllowed:
|
|
return generateMethodNotAllowedHTML(url)
|
|
case ErrorTypeInternalError:
|
|
return generateInternalErrorHTML(config.DebugMode, url, errMsg)
|
|
case ErrorTypeForbidden:
|
|
return generateForbiddenHTML(config.DebugMode, url, errMsg)
|
|
default:
|
|
// Fallback to internal error
|
|
return generateInternalErrorHTML(config.DebugMode, url, errMsg)
|
|
}
|
|
}
|
|
|
|
// NotFoundPage generates a 404 Not Found error page
|
|
func NotFoundPage(config ErrorPageConfig, url string) string {
|
|
return ErrorPage(config, ErrorTypeNotFound, url, "")
|
|
}
|
|
|
|
// MethodNotAllowedPage generates a 405 Method Not Allowed error page
|
|
func MethodNotAllowedPage(config ErrorPageConfig, url string) string {
|
|
return ErrorPage(config, ErrorTypeMethodNotAllowed, url, "")
|
|
}
|
|
|
|
// InternalErrorPage generates a 500 Internal Server Error page
|
|
func InternalErrorPage(config ErrorPageConfig, url string, errMsg string) string {
|
|
return ErrorPage(config, ErrorTypeInternalError, url, errMsg)
|
|
}
|
|
|
|
// ForbiddenPage generates a 403 Forbidden error page
|
|
func ForbiddenPage(config ErrorPageConfig, url string, errMsg string) string {
|
|
return ErrorPage(config, ErrorTypeForbidden, url, errMsg)
|
|
}
|
|
|
|
// generateInternalErrorHTML creates a 500 Internal Server Error page
|
|
func generateInternalErrorHTML(debugMode bool, url string, errMsg string) string {
|
|
errorMessages := []string{
|
|
"Oops! Something went wrong",
|
|
"Oh no! The server choked",
|
|
"Well, this is embarrassing...",
|
|
"Houston, we have a problem",
|
|
"Gremlins in the system",
|
|
"The server is taking a coffee break",
|
|
"Moonshark encountered a lunar eclipse",
|
|
"Our code monkeys are working on it",
|
|
"The server is feeling under the weather",
|
|
"500 Brain Not Found",
|
|
}
|
|
|
|
randomMessage := errorMessages[rand.Intn(len(errorMessages))]
|
|
return generateErrorHTML("500", randomMessage, "Internal Server Error", debugMode, errMsg)
|
|
}
|
|
|
|
// generateForbiddenHTML creates a 403 Forbidden error page
|
|
func generateForbiddenHTML(debugMode bool, url string, errMsg string) string {
|
|
errorMessages := []string{
|
|
"Access denied",
|
|
"You shall not pass",
|
|
"This area is off-limits",
|
|
"Security check failed",
|
|
"Invalid security token",
|
|
"Request blocked for security reasons",
|
|
"Permission denied",
|
|
"Security violation detected",
|
|
"This request was rejected",
|
|
"Security first, access second",
|
|
}
|
|
|
|
defaultMsg := "Invalid or missing CSRF token. This could be due to an expired form or a cross-site request forgery attempt."
|
|
if errMsg == "" {
|
|
errMsg = defaultMsg
|
|
}
|
|
|
|
randomMessage := errorMessages[rand.Intn(len(errorMessages))]
|
|
return generateErrorHTML("403", randomMessage, "Forbidden", debugMode, errMsg)
|
|
}
|
|
|
|
// generateNotFoundHTML creates a 404 Not Found error page
|
|
func generateNotFoundHTML(url string) string {
|
|
errorMessages := []string{
|
|
"Nothing to see here",
|
|
"This page is on vacation",
|
|
"The page is missing in action",
|
|
"This page has left the building",
|
|
"This page is in another castle",
|
|
"Sorry, we can't find that",
|
|
"The page you're looking for doesn't exist",
|
|
"Lost in space",
|
|
"That's a 404",
|
|
"Page not found",
|
|
}
|
|
|
|
randomMessage := errorMessages[rand.Intn(len(errorMessages))]
|
|
return generateErrorHTML("404", randomMessage, "Page Not Found", false, url)
|
|
}
|
|
|
|
// generateMethodNotAllowedHTML creates a 405 Method Not Allowed error page
|
|
func generateMethodNotAllowedHTML(url string) string {
|
|
errorMessages := []string{
|
|
"That's not how this works",
|
|
"Method not allowed",
|
|
"Wrong way!",
|
|
"This method is not supported",
|
|
"You can't do that here",
|
|
"Sorry, wrong door",
|
|
"That method won't work here",
|
|
"Try a different approach",
|
|
"Access denied for this method",
|
|
"Method mismatch",
|
|
}
|
|
|
|
randomMessage := errorMessages[rand.Intn(len(errorMessages))]
|
|
return generateErrorHTML("405", randomMessage, "Method Not Allowed", false, url)
|
|
}
|
|
|
|
// generateErrorHTML creates the common HTML structure for error pages
|
|
func generateErrorHTML(errorCode, mainMessage, subMessage string, showDebugInfo bool, codeContent string) string {
|
|
errorHTML := `<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>` + errorCode + `</title>
|
|
<style>
|
|
:root {
|
|
--bg-color: #2d2e2d;
|
|
--bg-gradient: linear-gradient(to bottom, #2d2e2d 0%, #000 100%);
|
|
--text-color: white;
|
|
--code-bg: rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
--bg-color: #f5f5f5;
|
|
--bg-gradient: linear-gradient(to bottom, #f5f5f5 0%, #ddd 100%);
|
|
--text-color: #333;
|
|
--code-bg: rgba(0, 0, 0, 0.1);
|
|
}
|
|
}
|
|
|
|
body {
|
|
font-family: sans-serif;
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
margin: 0;
|
|
background-color: var(--bg-color);
|
|
color: var(--text-color);
|
|
background: var(--bg-gradient);
|
|
}
|
|
h1 {
|
|
font-size: 4rem;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
p {
|
|
font-size: 1.5rem;
|
|
margin: 0.5rem 0;
|
|
padding: 0;
|
|
}
|
|
.sub-message {
|
|
font-size: 1.2rem;
|
|
margin-bottom: 1rem;
|
|
opacity: 0.8;
|
|
}
|
|
code {
|
|
display: inline-block;
|
|
font-size: 1rem;
|
|
font-family: monospace;
|
|
background-color: var(--code-bg);
|
|
padding: 0.25em 0.5em;
|
|
border-radius: 0.25em;
|
|
margin-top: 1rem;
|
|
max-width: 90vw;
|
|
overflow-wrap: break-word;
|
|
word-break: break-all;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div>
|
|
<h1>` + errorCode + `</h1>
|
|
<p>` + mainMessage + `</p>
|
|
<div class="sub-message">` + subMessage + `</div>`
|
|
|
|
if codeContent != "" {
|
|
errorHTML += `
|
|
<code>` + codeContent + `</code>`
|
|
}
|
|
|
|
// Add a note for debug mode
|
|
if showDebugInfo {
|
|
errorHTML += `
|
|
<p style="font-size: 0.9rem; margin-top: 1rem;">
|
|
An error occurred while processing your request.<br>
|
|
Please check the server logs for details.
|
|
</p>`
|
|
}
|
|
|
|
errorHTML += `
|
|
</div>
|
|
</body>
|
|
</html>`
|
|
|
|
return errorHTML
|
|
}
|